Использование метода Python list index() для списка кортежей или объектов?
-
09-09-2019 - |
Вопрос
Тип списка 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 уже есть способ сделать это.
Решение
Как насчет этого?
>>> 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
Одной из возможностей является использование получатель предметов функция от 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]
Вы можете сделать это с помощью понимания списка и index().
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
Я бы разместил это как комментарий к Триптиху, но пока не могу комментировать из-за отсутствия рейтинга:
Использование метода перечислителя для сопоставления подиндексов в списке кортежей.например
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)]
>>> 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
ок, возможно это ошибка 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
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')]
Никто не предлагает лямбды?
Попробуйте это, и это работает.Я прихожу к этому посту в поисках ответа.Не нашел того, что мне нравится, но чувствую что-то :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]]
извлечь все элементы по условию:filter(lambda 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]]
Примечание:_ переменная работает только в интерактивном интерпретаторе и обычном текстовом файле _ необходимо явно назначить, т.е. _=filter(lambda x:x[1][0]=="pato", enumerate(l))
List.index(x) Python возвращает индекс первого вхождения 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]
Я думаю, что следующий способ — не лучший способ сделать это (проблемы скорости и элегантности), но это может помочь:
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 на лету.