【问题标题】:Python: Merge sub-product of multiple lists of different length into a list of tuplesPython:将多个不同长度列表的子产品合并到一个元组列表中
【发布时间】:2017-07-27 14:44:43
【问题描述】:

我正在尝试使用以下方法将多个不同长度列表的子产品合并到元组列表中:

import itertools

letters = ['a', 'b', 'c']
symbols = ['*', '#', '+']
numbers = [1, 2, 3, 4, 5]

tuples_of_two = zip(letters, symbols)
tuples_of_three = list(itertools.product(tuples_of_two, numbers))

print(tuples_of_three)

产生一个包含元组和数字的元组列表:

[(('a', '*'), 1),
 (('a', '*'), 2),
 (('a', '*'), 3),
 (('a', '*'), 4),
 (('a', '*'), 5),
 (('b', '#'), 1),
 (('b', '#'), 2),
 (('b', '#'), 3),
 (('b', '#'), 4),
 (('b', '#'), 5),
 (('c', '+'), 1),
 (('c', '+'), 2),
 (('c', '+'), 3),
 (('c', '+'), 4),
 (('c', '+'), 5)]

但实际上我正在尝试获得以下结果,这是一个没有“子元组”的元组列表:

[('a', '*', 1),
 ('a', '*', 2),
 ('a', '*', 3),
 ('a', '*', 4),
 ('a', '*', 5),
 ('b', '#', 1),
 ('b', '#', 2),
 ('b', '#', 3),
 ('b', '#', 4),
 ('b', '#', 5),
 ('c', '+', 1),
 ('c', '+', 2),
 ('c', '+', 3),
 ('c', '+', 4),
 ('c', '+', 5)]

并不是说在元组中我只想要'a'与'*'组合,'b'与'#'和'c'与'+'所以它不是intertools.product可以达到的完整产品.

这可能可以通过使用一些“untuples”元组的第一个元素或者更优雅的直接方式来实现。

但我现在卡住了..

谁能帮忙?

提前致谢!

【问题讨论】:

  • [(letters[i], symbols[i], n) for i,n in itertools.product(range(len(letters)), numbers)]
  • flatten_tuple = lambda (nested, outer_scalar): nested + (outer_scalar,),以防万一。
  • “我不相信这真的是你想要的。你真的想要 a only 与 * 结合吗?不与 # 或 + 结合?”正如解释的那样,我不希望它带有 # 或 + 。 @Stefan Pochmann:您现在是否因为我的反应时间不够快而投了反对票?
  • 感谢您的所有回答!这节省了我的时间。
  • @Stefan Pochmann:请您再次投票!?我想这个问题很有价值,因为我在 SO 上没有找到任何关于此的内容。

标签: python list itertools


【解决方案1】:

itertools.product 与嵌套的 for 循环做同样的事情。您可以使用带有zip 的直接列表理解来一次性实现您所需要的:

[(l, s, n) for l, s in zip(letters, symbols) for n in numbers]

#[('a', '*', 1),
# ('a', '*', 2),
# ('a', '*', 3),
# ('a', '*', 4),
# ('a', '*', 5),
# ('b', '#', 1),
# ...

【讨论】:

  • 您的回答基本上将我的代码减少了大约。 60%。再次感谢!
【解决方案2】:

您可以通过构建一个将内部元组添加到单例元组的新元组来展平元组:

tuples_of_three =  [x+(y,) for x, y in itertools.product(tuples_of_two, numbers)]

【讨论】:

  • 感谢您的回答。我选择了 Psidoms 的答案,因为我什至不需要 intertools。但你的也很好用!
【解决方案3】:

摘自itertools.product() 文档:

product(A, B) 返回相同的结果:((x,y) for x in A for y in B)

因此,您可以这样做:

letters = ['a', 'b', 'c']
symbols = ['*', '#', '+']
numbers = [1, 2, 3, 4, 5]

print([(letter, symbol, number) for letter, symbol in zip(letters, symbols) for number in numbers])

【讨论】:

  • 这是一个不错的解决方案,与 Psidoms 相同!
【解决方案4】:

一个有点“通用”的解决方案,也使用zip(numbers) 将数字包装在元组中。那么你统一只有元组,它们可以简单地相加。

>>> if 1:
    import itertools, pprint

    letters = ['a', 'b', 'c']
    symbols = ['*', '#', '+']
    numbers = [1, 2, 3, 4, 5]
    zips = zip(letters, symbols), zip(numbers)

    result = [sum(p, ()) for p in itertools.product(*zips)]

    pprint.pprint(result)


[('a', '*', 1),
 ('a', '*', 2),
 ('a', '*', 3),
 ('a', '*', 4),
 ('a', '*', 5),
 ('b', '#', 1),
 ('b', '#', 2),
 ('b', '#', 3),
 ('b', '#', 4),
 ('b', '#', 5),
 ('c', '+', 1),
 ('c', '+', 2),
 ('c', '+', 3),
 ('c', '+', 4),
 ('c', '+', 5)]
>>> 

这也适用于更复杂的组合,你只需要定义它们,例如:

    zips = zip(letters, symbols), zip(numbers), zip(symbols, letters, numbers)

如果您有更多/更长的元组,则将它们链接可能会更有效:

    result = [tuple(itertools.chain.from_iterable(p))
              for p in itertools.product(*zips)]

【讨论】:

    【解决方案5】:
    tuples_of_three = list(itertools.product(letters, symbols, numbers))
    

    它应该适合你:

    ('a', '*', 1)
    ('a', '*', 2)
    ('a', '*', 3)
    ('a', '*', 4)
    ('a', '*', 5)
    ('a', '#', 1)
    ('a', '#', 2)
    ('a', '#', 3)
    ('a', '#', 4)
    ('a', '#', 5)
    ('a', '+', 1)
    ('a', '+', 2)
    ('a', '+', 3)
    ('a', '+', 4)
    ('a', '+', 5)
    ('b', '*', 1)
    ('b', '*', 2)
    ('b', '*', 3)
    ('b', '*', 4)
    ('b', '*', 5)
    ('b', '#', 1)
    ('b', '#', 2)
    ...
    

    【讨论】:

    • 我想这就是 OP 真正想要的,@StefanPochmann 的评论是正确的,他真的想要 a 只与 * 结合,而不是与 #+ 结合吗?
    • 不带 # 和 + 所以答案不是我想要的。还是谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-30
    • 1970-01-01
    • 1970-01-01
    • 2019-10-16
    • 2021-09-12
    • 2017-12-04
    • 1970-01-01
    相关资源
    最近更新 更多