【问题标题】:Modify list of sets containing sets in Python3在 Python3 中修改包含集合的集合列表
【发布时间】:2020-06-17 00:49:09
【问题描述】:

我正在尝试创建一个以元组作为元素的列表。每个元组有 4 个整数。前 2 个整数是压缩 2 个ranges 的结果,而另外 2 个来自 2 个不同的整数。

我正在使用此代码创建元组和最终列表,该列表源自笛卡尔积,如下所示:Get the cartesian product of a series of lists?

import itertools
first_range = list(zip((10**exp for exp in range(0,7)),(10**exp for exp in range(1,8))))
second_range = list(zip((5*10**exp if exp != 1 else 10**2 for exp in range(1,8)),(5*10**exp for exp in range(2,9))))
final_list = list(itertools.product(first_range,second_range))

这段代码的问题是最终结果看起来像这样:

[((1, 10), (100, 500)), ((1, 10), (500, 5000)), ((1, 10), (5000, 50000)), ((1, 10), (50000, 500000)), ((1, 10), (500000, 5000000)), ((1, 10), (5000000, 50000000)), ...

每个列表元素是一个包含 2 个其他元组的元组,而我想要的是:

[(1, 10, 100, 500), (1, 10, 500, 5000), (1, 10, 5000, 50000), (1, 10, 50000, 500000), (1, 10, 500000, 5000000), (1, 10, 5000000, 50000000), ...

即每个列表元素都是一个包含 4 个整数的元组。

任何想法将不胜感激。必须在 python3 上工作。 编辑:感谢 ShadowRanger 的 cmets,更新了代码的非工作部分

【问题讨论】:

  • 旁注:exp is not 1 是错误的。由于int 缓存很小,它可能在 CPython 上 99% 的时间都有效,但这是一个你不应该依赖的实现细节。 is/is not 仅适用于语言保证的单例(例如NoneNotImplemented),而不是ints。你想要exp != 1
  • @ShadowRanger 感谢您的信息。

标签: python python-3.x tuples cartesian-product


【解决方案1】:

所以,一旦我发布了这个问题,我就确定我已经接近答案了,但我没有意识到我已经这么接近了。解决额外元组问题的方法是:

import itertools
first_range = zip((10**exp for exp in range(7)),(10**exp for exp in range(1,8)))
second_range = zip((5*10**exp if exp != 1 else 10**2 for exp in range(1,8)),(5*10**exp for exp in range(2,9)))
iterator_of_tuples = itertools.product(first_range,second_range)

# the next line solves my issue
final_list = [x + y for x, y in iterator_of_tuples]

我所做的是一个简单的元组合并:How to merge two tuples in Python?。不知道为什么我没有早点想到它

编辑:根据 ShadowRanger 的输入更新答案

【讨论】:

  • 此代码不起作用; itertools.product 不返回 list,因此索引它不起作用(list_with_tuples 用词不当;它实际上是 iterator_of_tuples)。你可以让它工作,并更有效地运行,只需:final_list = [x + y for x, y in list_with_tuples](或final_list = list(itertools.starmap(operator.concat, list_with_tuples)),将所有工作推到 C 层)。
  • @ShadowRanger 你是对的我忘了在我的问题中添加一些东西。现在已修复。也是的,我总是忘记在 for 循环中获取 2 个变量
  • K.正如您所知,for i in range(len(seq)) 是 Python 中的反模式;来自 C 和其他没有本机迭代的语言的人使用它,但在 Python 中它又慢又丑。几乎总是有更好的方法,直接迭代(如我的示例)zipenumerate,或者如果这些都不够,可以使用 itertools API 之一。我所知道的唯一真正的例外是迭代序列的切片,其中非基于range 的解决方案明显丑陋,只有在您需要处理任意可迭代对象(切片不是选项)时才值得。
  • 这基本上是我的答案,多了 1 行无用的代码
  • @MarcoZamboni 您的回答会生成一个包含 7 个元素的列表,这是不正确的。
【解决方案2】:

您的预期输出不是两个范围的笛卡尔积。

如果你想要你的预期输出,这样的事情会起作用:

final_list = [(*x, *y) for x, y in zip(first_range, second_range)]

【讨论】:

  • 它不是笛卡尔积,它不区分 (a,b) 和 (b,a),对吗?如果是这样,那没关系,我得到itertools 库正在产品末尾执行 set()。
  • @CnewbieWannabePro: itertoolssets 没有任何作用,我不知道你为什么认为它会这样做。
  • @CnewbieWannabePro 不,它不是笛卡尔积,因为你想合并元组
猜你喜欢
  • 2020-09-13
  • 2022-07-17
  • 2011-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多