一个简单的字典理解应该可以解决问题:
{key: [index for index, x in enumerate(my_list) if x == key] for key in my_list}
一个简单的试验:
>>>> my_list = ['A','B','A','B']
>>>> {key: [index for index, x in enumerate(my_list) if x == key] for key in my_list}
>>>> {'A': [0, 2], 'B': [1, 3]}
工作原理
List comprehensions 通常在 Python 中用作 for 循环的语法糖。而不是写
my_list = []
for item in range(10):
my_list.append(item)
列表推导本质上可以让您将这一系列语句压缩成一行:
my_list = [item for item in range(10)]
当您看到列表推导式时,您应该记住它只是原始三行语句的精简版本。它们实际上是相同的 - 这里提供的唯一好处是简洁。
一个类似的相关物种是dictionary comprehension。它类似于列表推导式,只是它允许您同时指定 both 键和值。
一个字典理解的例子:
{k: None for k in ["Hello", "Adele"]}
>>>> {"Hello": None, "Adele": None}
在我提供的答案中,我只是使用了一个字典理解
- 从
my_list拉出keys
- 为来自
my_list 的每个key 分配一个索引列表作为对应值
从句法上讲,它扩展为一个相当复杂的程序,如下所示:
my_dict = {}
for key in my_list:
indices = []
for index,value in enumerate(my_list):
if value == key:
indices.append(index)
my_dict[key] = indices
这里,enumerate 是一个标准库函数,它返回一个元组列表。每个元组的第一个元素引用列表的索引,第二个元素引用列表中该索引处的值。
观察:
enumerate(['a','b','a','b'])
>>>> [(0,'a'),(1,'b'),(2,'b'),(3,'b')]
这就是enumerate 的力量。
效率
与往常一样,过早优化是万恶之源。确实,这种实现效率低下:它重复工作,并且在二次时间中运行。然而,重要的是询问您的特定任务是否可以。对于相对较小的列表,这已经足够了。
您可以查看某些优化。 @wilinx 的方法效果很好。 cmets 中的@Rob 建议对set(my_list) 进行迭代,这样可以防止重复工作。