映射两个列表而不循环

时间:2016-04-24 11:25:42

标签: python

我有两个相等长度的列表。第一个列表l1包含数据。

l1 = [2, 3, 5, 7, 8, 10, ... , 23]

第二个列表l2包含l1中的数据所属的类别:

l2 = [1, 1, 2, 1, 3, 4, ... , 3]

如何使用列表理解 lambda函数,根据第二个列表中1, 2, 3, 4等数字定义的位置对第一个列表进行分区。例如,第一个列表中的2, 3, 7属于同一个分区,因为它们在第二个列表中具有相应的值。

分区数在开始时就已知。

7 个答案:

答案 0 :(得分:9)

您可以使用字典:

>>> l1 = [2, 3, 5, 7, 8, 10, 23] 
>>> l2 = [1, 1, 2, 1, 3, 4, 3]

>>> d = {}
>>> for i, j in zip(l1, l2):
...     d.setdefault(j, []).append(i)
... 
>>> 
>>> d
{1: [2, 3, 7], 2: [5], 3: [8, 23], 4: [10]}

答案 1 :(得分:8)

如果dict没问题,我建议使用defaultdict

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> for number, category in zip(l1, l2):
...     d[category].append(number)
... 
>>> d
defaultdict(<type 'list'>, {1: [2, 3, 7], 2: [5], 3: [8, 23], 4: [10]})

如果您使用的是Python 2,请考虑使用itertools.izip来提高内存效率。

这与Kasramvd的解决方案基本相同,但我认为defaultdict使其更容易阅读。

答案 2 :(得分:2)

这将使用列表解析提供分区列表:

>>> l1 = [2, 3, 5, 7, 8, 10, 23] 
>>> l2 = [1, 1, 2, 1, 3, 4, 3]
>>> [[value for i, value in enumerate(l1) if j == l2[i]] for j in set(l2)]
[[2, 3, 7], [5], [8, 23], [10]]

答案 3 :(得分:1)

嵌套列表理解:

[ [ l1[j] for j in range(len(l1)) if l2[j] == i ] for i in range(1, max(l2)+1 )]

答案 4 :(得分:1)

如果将数据存储在numpy ndarrays 中是合理的,则可以使用扩展索引

{i:l1[l2==i] for i in set(l2)}

构建由类别代码索引的 ndarrays 字典。

l2==i相关联的开销(即,为每个类别构建新的布尔数组)随着类别数量的增长而增长,因此您可能想要检查哪个替代方案numpydefaultdict,您的数据更快。

我使用n=200000进行了测试,nc=20numpy的速度高于defaultdict + izip(124 vs 165 ms),但使用nc=10000 numpy(更慢)(11300 vs 251 ms)

答案 5 :(得分:1)

使用一些itertoolsoperator好东西,你可以在一个班轮内完成这项工作:

>>> l1 = [2, 3, 5, 7, 8, 10, 23] 
>>> l2 = [1, 1, 2, 1, 3, 4, 3]
>>> itertools.groupby(sorted(zip(l2, l1)), operator.itemgetter(0))

结果是itertools.groupby对象可以迭代:

>>> for g, li in itertools.groupby(sorted(zip(l2, l1)), operator.itemgetter(0)):
>>>     print(g, list(map(operator.itemgetter(1), li)))

1 [2, 3, 7]
2 [5]
3 [8, 23]
4 [10]

答案 6 :(得分:1)

这不是列表理解,而是字典理解。它类似于@ cromod的解决方案,但保留了l2的“类别”:

{k:[val for i, val in enumerate(l1) if k == l2[i]] for k in set(l2)}

输出:

>>> l1
[2, 3, 5, 7, 8, 10, 23]
>>> l2
[1, 1, 2, 1, 3, 4, 3]
>>> {k:[val for i, val in enumerate(l1) if k == l2[i]] for k in set(l2)}
{1: [2, 3, 7], 2: [5], 3: [8, 23], 4: [10]}
>>>