为包含列表的字典创建列表推导式

3 投票
2 回答
941 浏览
提问于 2025-04-29 17:49

我需要创建一个列表推导式,从一个嵌套的列表中提取字典的值。到目前为止,我的尝试都没有成功。这个对象看起来是这样的:

MyList=[[{'animal':'A','color':'blue'},{'animal':'B','color':'red'}],[{'animal':'C','color':'blue'},{'animal':'D','color':'Y'}]] 

我想提取字典/列表/列表中每个元素的值,这样我就能得到两个新的列表:

Animals=[[A,B],[C,D]]
Colors=[[blue,red],[blue,Y]]

有什么建议吗?不一定要用列表推导式;这只是我目前的起点。谢谢!

暂无标签

2 个回答

1

在一次赋值中(通过一个列表推导式,以及使用 mapzip 的帮助):

Colors, Animals =  map(list, 
                       zip(*[map(list, 
                                 zip(*[(d['color'], d['animal']) for d in a])) 
                             for a in MyList]))

如果你对元组没有意见,可以省去两次调用 map => list 的步骤。

编辑:

让我们详细看看,通过分解嵌套的推导式来理解。我们还假设 MyListm 个元素,总共有 n 个对象(字典)。

[[d for d in sub] for sub in MyList]

这段代码会遍历每个子列表中的字典。对于每个字典,我们创建一个包含它的 color 属性作为第一个元素,animal 属性作为第二个元素的元组:

(d['color'], d['animal'])

到目前为止,这个过程的时间复杂度是 O(n) - 实际上会处理 n 个元素。

print [[(d['color'], d['animal']) for d in sub] for sub in MyList]

现在,对于原始列表中的每个 m 个子列表,我们有一组元组需要进行 解压,也就是把它变成两个单独的列表。在 Python 中,解压 是通过 zip 函数来完成的,传入一组元组作为参数(第一个元组的元素个数决定了输出的元组数量)。例如,传入 3 个元组,我们会得到两个各有 3 个元素的列表。

>>> zip((1,2), (3,4), (5,6))  #Prints [(1, 3, 5), (2, 4, 6)]

为了将这个应用到我们的情况,我们需要将一组元组传递给 zip,作为可变数量的参数:这可以通过 splat 操作符来实现,也就是 *

[zip(*[(d['color'], d['animal']) for d in sub]) for sub in MyList]

这个操作需要遍历每个子列表一次,然后再遍历我们在前一步创建的每个元组。因此,总的运行时间是 O(n + n + m) = O(n),大约需要 2*n + 2*m 次操作。

到目前为止,我们有 m 个子列表,每个子列表包含两个元组(第一个元组会收集该子列表的所有颜色,第二个元组会收集所有动物)。为了得到两个各有 m 个元组的列表,我们再次进行解压。

zip(*[zip(*[(d['color'], d['animal']) for d in sub]) for sub in MyList]

这将需要额外的 m 步骤 - 所以运行时间仍然是 O(n),大约需要 2*n + 4*m 次操作。

为了简单起见,我们在这个分析中省略了将元组映射到列表的步骤 - 如果你对元组没意见,这样做是可以的。

不过,元组是不可变的,所以这可能不适用。如果你需要列表的列表,你需要对每个元组应用 list 函数:每个 m 个子列表一次(总共有 2*n 个元素),以及对每个第一层列表,即动物和颜色各一次(每个都有 m 个元素)。假设 list 的时间复杂度与它所应用的序列长度成正比,这个额外的步骤需要 2*n + 2*m 次操作,这仍然是 O(n)

5
Animals = [[d['animal'] for d in sub] for sub in MyList]
Colors = [[d['color'] for d in sub] for sub in MyList]

得到了想要的结果:

[['A', 'B'], ['C', 'D']]
[['blue', 'red'], ['blue', 'Y']]  # No second 'red'.

我在这里做的就是先拿到每个子列表,然后再拿到每个字典,最后访问正确的键。

撰写回答