我有一个列表:
input = ['a','b','c','a','b','d','e','d','g','g']
我想要所有元素的索引(列表中重复的元素除外)。
output = [0,1,2,5,6,8]
答案 0 :(得分:4)
您应该遍历枚举列表,然后将每个元素添加到一组“可见”元素中,并将索引添加到输出列表中。 如果尚未看到该元素(不在“看到的”集合)。
哦,名称input
将覆盖内置的input()
函数,因此我将其重命名为input_list
。
output = []
seen = set()
for i,e in enumerate(input_list):
if e not in seen:
output.append(i)
seen.add(e)
将output
设为[0, 1, 2, 5, 6, 8]
。
为什么要使用一套?
您可能在想,为什么可以使用一组东西,例如:
[i for i,e in enumerate(input_list) if input_list.index(e) == i]
之所以有效,是因为.index
返回具有该值的列表中第一个元素的索引,因此,如果您对照该元素检查元素的索引,则可以断言它是该元素的第一次出现元素并过滤掉不是第一次出现的那些元素。
但是,这不如使用集合有效,因为list.index
要求Python遍历列表,直到找到元素为止(或没有找到)。此操作的复杂度为O(n)
,由于我们为input_list
中的每个元素调用它,因此整个解决方案将为O(n^2)
。
另一方面,与第一个解决方案一样,使用集合将产生O(n)
解决方案,因为检查元素是否为in
集合就是复杂度O(1)
(平均情况)。这是由于集的实现方式(它们类似于列表,但是每个元素都存储在其哈希值的索引处,因此您可以计算元素的哈希值,然后查看是否存在某个元素来检查成员资格,而不用遍历它-请注意,这是一个模糊的过分简化,但这是他们的想法。
因此,由于对成员资格的每次检查都是O(1)
,并且我们对每个元素都执行此操作,所以我们得到的O(n)
解决方案比O(n^2)
解决方案好得多。
答案 1 :(得分:0)
您可以执行以下操作,检查计数(尽管这需要大量计算):
indexes = []
for i, x in enumerate(inputlist):
if (inputlist.count(x) == 1
and x not in inputlist[:i]):
indexes.append(i)
这将检查以下内容:
答案 2 :(得分:0)
如果您不介意最后一次出现重复的索引,而是使用Python 3.6+,则可以选择以下解决方案:
list(dict(map(reversed, enumerate(input))).values())
这将返回:
[3, 4, 2, 7, 6, 9]
答案 3 :(得分:0)
这里是使用zip
和reversed
的单线纸
>>> input = ['a','b','c','a','b','d','e','d','g','g']
>>> sorted(dict(zip(reversed(input), range(len(input)-1, -1, -1))).values())
[0, 1, 2, 5, 6, 8]
答案 4 :(得分:0)
此问题缺少pandas
解决方案。
>>> import pandas as pd
>>> inp = ['a','b','c','a','b','d','e','d','g','g']
>>>
>>> pd.DataFrame(list(enumerate(inp))).groupby(1).first()[0].tolist()
[0, 1, 2, 5, 6, 8]
答案 5 :(得分:0)
另一个版本,在列表理解中使用了副作用。
>>> xs=['a','b','c','a','b','d','e','d','g','g']
>>> seen = set()
>>> [i for i, v in enumerate(xs) if v not in seen and not seen.add(v)]
[0, 1, 2, 5, 6, 8]
列表推导过滤尚未出现的值的索引。
诀窍是not seen.add(v)
始终为true,因为seen.add(v)
返回None
。
由于存在短路评估,因此seen.add(v)
会在且仅当看不到v
时执行,从而会在seen
中动态添加新值。
最后,看到的内容包含输入列表的所有值。
>>> seen
{'a', 'c', 'g', 'b', 'd', 'e'}
注意:在列表理解中使用副作用通常是个坏主意, 但是有时您可能会看到这个窍门。