Использование метода Python list index() для списка кортежей или объектов?

Тип списка Python имеет метод index(), который принимает один параметр и возвращает индекс первого элемента в списке, соответствующем параметру. Например:

>>> some_list = ["apple", "pear", "banana", "grape"]
>>> some_list.index("pear")
1
>>> some_list.index("grape")
3

Есть ли изящный (идиоматический) способ расширить это на списки сложных объектов, таких как кортежи? В идеале я хотел бы иметь возможность сделать что-то вроде этого:

>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> some_list.getIndexOfTuple(1, 7)
1
>>> some_list.getIndexOfTuple(0, "kumquat")
2

getIndexOfTuple () - это просто гипотетический метод, который принимает субиндекс и значение, а затем возвращает индекс элемента списка с заданным значением в этом субиндексе. я надеюсь

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

13 ответов

Решение

Как насчет этого?

>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> [x for x, y in enumerate(tuple_list) if y[1] == 7]
[1]
>>> [x for x, y in enumerate(tuple_list) if y[0] == 'kumquat']
[2]

Как отмечено в комментариях, это получит все совпадения. Чтобы получить первый, вы можете сделать:

>>> [y[0] for y in tuple_list].index('kumquat')
2

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

Эти списки понимаются через некоторое время.

Мне нравится этот подход Pythonic:

from operator import itemgetter

def collect(l, index):
   return map(itemgetter(index), l)

# And now you can write this:
collect(tuple_list,0).index("cherry")   # = 1
collect(tuple_list,1).index("3")        # = 2

Если вам нужен ваш код, чтобы быть супер производительным:

# Stops iterating through the list as soon as it finds the value
def getIndexOfTuple(l, index, value):
    for pos,t in enumerate(l):
        if t[index] == value:
            return pos

    # Matches behavior of list.index
    raise ValueError("list.index(x): x not in list")

getIndexOfTuple(tuple_list, 0, "cherry")   # = 1

Одной из возможностей является использование функции itemgetter из operator модуль:

import operator

f = operator.itemgetter(0)
print map(f, tuple_list).index("cherry") # yields 1

Призыв к itemgetter возвращает функцию, которая будет делать эквивалент foo[0] за что-то переданное ему. С помощью mapЗатем вы применяете эту функцию к каждому кортежу, извлекая информацию в новый список, для которого затем вызываете index как обычно.

map(f, tuple_list)

эквивалентно:

[f(tuple_list[0]), f(tuple_list[1]), ...etc]

что в свою очередь эквивалентно:

[tuple_list[0][0], tuple_list[1][0], tuple_list[2][0]]

который дает:

["pineapple", "cherry", ...etc]

Вы можете сделать это с помощью понимания списка и индекса ()

tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
[x[0] for x in tuple_list].index("kumquat")
2
[x[1] for x in tuple_list].index(7)
1

Вдохновленный этим вопросом, я нашел это довольно элегантным:

>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> next(i for i, t in enumerate(tuple_list) if t[1] == 7)
1
>>> next(i for i, t in enumerate(tuple_list) if t[0] == "kumquat")
2

Я бы разместил это как комментарий к Триптиху, но пока не могу комментировать из-за отсутствия рейтинга:

Использование метода перечислителя для сопоставления по субиндексам в списке кортежей. например

li = [(1,2,3,4), (11,22,33,44), (111,222,333,444), ('a','b','c','d'),
        ('aa','bb','cc','dd'), ('aaa','bbb','ccc','ddd')]

# want pos of item having [22,44] in positions 1 and 3:

def getIndexOfTupleWithIndices(li, indices, vals):

    # if index is a tuple of subindices to match against:
    for pos,k in enumerate(li):
        match = True
        for i in indices:
            if k[i] != vals[i]:
                match = False
                break;
        if (match):
            return pos

    # Matches behavior of list.index
    raise ValueError("list.index(x): x not in list")

idx = [1,3]
vals = [22,44]
print getIndexOfTupleWithIndices(li,idx,vals)    # = 1
idx = [0,1]
vals = ['a','b']
print getIndexOfTupleWithIndices(li,idx,vals)    # = 3
idx = [2,1]
vals = ['cc','bb']
print getIndexOfTupleWithIndices(li,idx,vals)    # = 4
tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]

def eachtuple(tupple, pos1, val):
    for e in tupple:
        if e == val:
            return True

for e in tuple_list:
    if eachtuple(e, 1, 7) is True:
        print tuple_list.index(e)

for e in tuple_list:
    if eachtuple(e, 0, "kumquat") is True:
        print tuple_list.index(e)
z = list(zip(*tuple_list))
z[1][z[0].index('persimon')]

Хорошо, это может быть ошибкой в vals(j)коррекция:

def getIndex(li,indices,vals):
for pos,k in enumerate(lista):
    match = True
    for i in indices:
        if k[i] != vals[indices.index(i)]:
            match = False
            break
    if(match):
        return pos

Я придумал быстрый и грязный подход, используя maxа также lambda.

      >>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> target = 7
>>> max(range(len(tuple_list)), key=lambda i: tuple_list[i][1] == target)
1

Однако есть предостережение: если список не содержит цели, возвращаемый индекс будет 0, что может ввести в заблуждение.

      >>> target = -1
>>> max(range(len(tuple_list)), key=lambda i: tuple_list[i][1] == target)
0

Я думаю, что следующее не лучший способ сделать это (проблемы со скоростью и элегантностью), но это может помочь:

from collections import OrderedDict as od
t = [('pineapple', 5), ('cherry', 7), ('kumquat', 3), ('plum', 11)]
list(od(t).keys()).index('kumquat')
2
list(od(t).values()).index(7)
7
# bonus :
od(t)['kumquat']
3

Список кортежей с двумя членами может быть преобразован в упорядоченный dict напрямую, структуры данных фактически одинаковы, поэтому мы можем использовать метод dict на лету.

Тело не предлагает лямбды?

У попробуйте это и работает. Я пришел к этому посту в поисках ответа. Я не нашел, что мне нравится, но я чувствую инсайт:P

    l #[['rana', 1, 1], ['pato', 1, 1], ['perro', 1, 1]]

    map(lambda x:x[0], l).index("pato") #1 

Изменить, чтобы добавить примеры:

   l=[['rana', 1, 1], ['pato', 2, 1], ['perro', 1, 1], ['pato', 2, 2], ['pato', 2, 2]]

извлечь все элементы по условию: фильтр (лямбда-x:x[0]=="pato", l) #[['pato', 2, 1], ['pato', 2, 2], ['pato', 2, 2]]

извлечь все элементы по условию с индексом:

    >>> filter(lambda x:x[1][0]=="pato", enumerate(l))
    [(1, ['pato', 2, 1]), (3, ['pato', 2, 2]), (4, ['pato', 2, 2])]
    >>> map(lambda x:x[1],_)
    [['pato', 2, 1], ['pato', 2, 2], ['pato', 2, 2]]

Примечание:_ переменная работает только в интерактивном интерпретаторе y обычный текстовый файл _ требуется явное присвоение, т. Е. _= Фильтр (лямбда-x:x[1][0]=="pato", перечислить (l))

Python's list.index(x) возвращает индекс первого вхождения x в списке. Таким образом, мы можем передать объекты, возвращенные сжатием списка, чтобы получить их индекс.

>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> [tuple_list.index(t) for t in tuple_list if t[1] == 7]
[1]
>>> [tuple_list.index(t) for t in tuple_list if t[0] == 'kumquat']
[2]

С помощью той же строки мы также можем получить список индексов в случае, если имеется несколько совпадающих элементов.

>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11), ("banana", 7)]
>>> [tuple_list.index(t) for t in tuple_list if t[1] == 7]
[1, 4]
Другие вопросы по тегам