Есть ли в Python способ индексировать список контейнеров (кортежей, списков, словарей) по элементу контейнера? - PullRequest
1 голос
/ 28 мая 2009

Я искал рецепт / пример для индексации списка кортежей, не применяя модификацию подхода decorate, sort, undecorate.

Например:

l=[(a,b,c),(x,c,b),(z,c,b),(z,c,d),(a,d,d),(x,d,c) . . .]

Подход, который я использовал, состоит в том, чтобы создать словарь, используя defaultdict из второго элемента

from collections import defaultdict

tdict=defaultdict(int)

for myTuple in l:
    tdict[myTuple[1]]+=1

Затем я должен построить список, состоящий только из второго элемента в кортеже для каждого элемента в списке. В то время как есть несколько способов добраться, простой подход заключается в следующем:

tempList=[myTuple[1] for myTuple in l]

, а затем сгенерировать индекс каждого элемента в tdict

indexDict=defaultdict(dict)
for key in tdict:
    indexDict[key]['index']=tempList.index(key)

Ясно, что это не похоже на Pythonic. Я пытался найти примеры или идеи, думая, что я смогу использовать что-то волшебное, чтобы получить индекс напрямую. Пока такой удачи нет.

Заметьте, я понимаю, что могу использовать свой подход немного более прямо и не генерировать тдикт.

выводом может быть словарь с индексом

indexDict={'b':{'index':0},'c':{'index':1},'d':{'index':4},. . .}

Изучив много ответов Нади, я думаю, что ответ - нет.

Хотя ее ответ работает, я думаю, что он сложнее, чем нужно. Я бы просто

 def build_index(someList):
    indexDict={}
    for item in enumerate(someList):
        if item[1][1] not in indexDict:
           indexDict[item[1][1]]=item[0]
    return indexDict

Ответы [ 2 ]

5 голосов
/ 28 мая 2009

Это приведет к желаемому результату

dict((myTuple[1], index) for index, myTuple in enumerate(l))

>>> l = [(1, 2, 3), (4, 5, 6), (1, 4, 6)]
>>> dict((myTuple[1], index) for index, myTuple in enumerate(l))
{2: 0, 4: 2, 5: 1}

И если вы настаиваете на использовании словаря для представления индекса:

dict((myTuple[1], {'index': index}) for index, myTuple in enumerate(l))

Результат будет:

{2: {'index': 0}, 4: {'index': 2}, 5: {'index': 1}}

EDIT Если вы хотите справиться со столкновением клавиш, вам придется расширить решение следующим образом:

def build_index(l):
    indexes = [(myTuple[1], index) for index, myTuple in enumerate(l)]
    d = {}
    for e, index in indexes:
        d[e] = min(index, d.get(e, index))
    return d

>>> l = [(1, 2, 3), (4, 5, 6), (1, 4, 6), (2, 4, 6)]
>>> build_index(l)
{2: 0, 4: 2, 5: 1}

РЕДАКТИРОВАТЬ 2

И более обобщенное и компактное решение (по аналогии с sorted )

def index(l, key):
    d = {}
    for index, myTuple in enumerate(l):
        d[key(myTuple)] = min(index, d.get(key(myTuple), index))
    return d

>>> index(l, lambda a: a[1])
{2: 0, 4: 2, 5: 1}

Итак, ответ на ваш вопрос - да: в Python есть способ индексировать список контейнеров (кортежей, списков, словарей) по элементу контейнера без предварительной обработки. Но ваш запрос на сохранение результата в словаре лишает возможности быть одним вкладчиком. Но здесь нет предварительной обработки. Список повторяется только один раз.

0 голосов
/ 28 мая 2009

Если я думаю, что это то, что вы спрашиваете ...

l = ['asd', 'asdxzc']
d = {}

for i, x in enumerate(l):
    d[x] = {'index': i}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...