【问题标题】:How do I combine unique values from a list of tuples?如何组合元组列表中的唯一值?
【发布时间】:2019-05-25 15:32:57
【问题描述】:

我有 2 个列表(来自一个 excel 文件),其中一个包含产品名称,另一个包含数字。

示例 Excel 文件:

这意味着我有 2 个列表 - 使用 xlrd.col_values():

products = ['Product1','Product1','Product1','Product2','Product2','Product2']
values = [1,-1,0,2,4,-1]

我想要的最终结果是这样的:

format = [['Product1', [1,-1,0]],['Product2', [2,4,-1]]]

我曾尝试使用 zip() 来做到这一点:

zip_list = list(zip(products, values))

然而这返回了:

[('Product1', 1), ('Product1', -1), ('Product1', 0), ('Product2', 2), ('Product2', 4), ('Product2', -1)]

有人知道如何获得所需的格式吗? - 我正在使用python3。

【问题讨论】:

  • 你是从zip() 那里得到的,因为这正是它的作用。
  • @pstatix ,是的,对不起,我应该提到我以前从未使用过 zip 并且只是将其发布在那里,以防万一有办法使用 zip() 函数来创建它。 ...

标签: python arrays python-3.x list tuples


【解决方案1】:

您可以使用字典(理想:collections.defaultdict)来收集数据,然后使用 dict.items() 创建您的格式:

from collections import defaultdict

products = ['Product1','Product1','Product1','Product2','Product2','Product2']
values = [1,-1,0,2,4,-1]

d = defaultdict(list)
# accumulate your data
for prod,val in zip(products,values):
    d[prod].append(val)

print(d)   

# convert dict.items() to your wanted format    
format = [list(i) for i in d.items()] 
print(format)   

输出:

defaultdict(<class 'list'>, {'Product1': [1, -1, 0], 'Product2': [2, 4, -1]})

[['Product1', [1, -1, 0]], ['Product2', [2, 4, -1]]]

使用defaultdict(list) 优于dict.setdefault(key,[]) 或使用try: except: 或测试key in dict,因为它总体上比任何其他方法更快(内置优化)。

独库:


您还可以利用itertools.groupby() 对已排序数据(您的已已排序)进行操作以获得相同的结果:

from itertools import groupby

grped = groupby( zip(products,values), lambda x:x[0]) # group by 1st value

l = []
for g in grped:
    l.append([g[0],list(val for _,val in g[1])])      # extract 2nd value from grouping

print(l) # [['Product1', [1, -1, 0]], ['Product2', [2, 4, -1]]]

在此列表中使用 groupby 会创建相同的分区,因为它已排序 - 如果未排序,您会得到不同的结果。

【讨论】:

  • 我认为itertools.groupby 是这个问题的规范答案,我什至会考虑先列出它。另外,我可能会将“排序”更改为“分组”。数据不需要排序 - 唯一的要求是第一列中的值是分组的(即不交织)。
  • Nit, l = [[g[0], [v for _, v in g[1]] for g in grped] 可能更简洁。
  • @JaredGoguen groupby 需要排序数据 - 它只会创建连续值组:groupby( zip([1,1,1,2,2,2,1,1,1],[1,1,1,2,2,2,3,3,3]) ==&gt; [[1, [1, 1, 1]], [2, [2, 2, 2]], [1, [3, 3, 3]]] 将为键 1 创建 2 个组 - 默认字典不需要预排序:[[1, [1, 1, 1, 3, 3, 3]], [2, [2, 2, 2]]]
  • 使用[2, 2, 2, 1, 1, 1, 3, 3, 3] 作为第一个列表中的条目应该可以正常工作 - 这些没有排序
  • @Jared - 它们不需要排序 - 它们不共享相同的键这就是重点 - groupby 将一个键的 all 分组到一个分组中需要排序 - dict 方法不需要。因此,如果您不希望在不同的分组中使用相同的键,则需要首先对 groupby 进行排序,这会增加解决方案的复杂性 - 如果您可以在其他组位于连续键拉伸之间时在不同的分组中使用相同的键,您不需要...因此这取决于您想要什么以及您需要什么。这两种方法的价值取决于您想要的结果。
【解决方案2】:

由于字典理解不利于聚合,所以使用线性时间循环:

prods = {}
for item in zip(products, values):
    prod, val = item
    try:
        prods[prod].append(val)
    except KeyError:
        prods[prod] = [val]

# Sample
>>> prods = {}
>>> for item in zip(products, values):
    prod, val = item
    try:
        prods[prod].append(val)
    except KeyError:
        prods[prod] = [val]     
>>> prods
{'Product1': [1, -1, 0], 'Product2': [2, 4, -1]}

我知道您想要[['ProductN', [ ]] 的格式,但我认为字典是更好的选择。

【讨论】:

  • 非常感谢,这很好用,如果我有超过 2 个数组,例如得到:{Product:[[array1],[array2]]} 代替......不过,您的答案确实很好……
  • @wowcha 您最初的问题并不要求每个键需要两个列表。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-11
  • 1970-01-01
  • 2020-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多