【问题标题】:Clean dynamically generated nested Tuples清理动态生成的嵌套元组
【发布时间】:2016-04-24 20:13:20
【问题描述】:

我有一个类,其__iter__() 方法返回动态生成数据的itertools.product()。 这些数据是任意嵌套字典的笛卡尔积,现在我需要将它展平,但是以一种流线型的方式,聚合中间迭代器。

我正在尝试以下任何一种:

  1. 修改__iter__()以处理内部元组:

     class Explosion:
         ...
         def __iter__(self):
             return product(*self.fragments)
    
  2. 将其封装在另一个对象中以处理转换,但这不太理想:

     class CleanOutput:
         def __init__(self, it):
             self.it = it
    
         def next(self):
             for x in self.it:
                 yield ?
    
     class Explosion:
         ...
         def __iter__(self):
             return CleanOutput(product(*self.fragments))
    

好吧,算法确实有效,但问题是最后的拆包,例如:

(11, ..., (10.7, 104.75, ('N', True, False, 'B2B'), 99.01, ...), 1, 'SP', 7).

看看所有的嵌套!如何在real-time 中删除它?在生成时... 我正在寻找一种检索方式:

(11, ..., 10.7, 104.75, 'N', True, False, 'B2B', 99.01, ..., 1, 'SP', 7).

最好和最快的方法是什么? 谢谢!

编辑

实际上,我真正想要的是列表推导式或生成器表达式,甚至是另一个生成器,因为我需要将它包含在一个可调用对象中,截取itertools.product() 本身的输出.我不只是需要一种方式来清理这些元组。所以它不是重复的。

【问题讨论】:

  • 你能展示你的代码,你是如何达到第一个结果的吗?
  • 对不起@Kasramvd,我不能。但它并没有那么复杂,它是一个简单的 flatten dict 算法,有一些曲折,比如检测你什么时候有一个序列,获取并尝试它的一个元素,如果它是原语,将它们存储在 itertools.product 中使用,如果它是一个嵌套的 dict 那就更难了,因为你必须为每个条目创建另一个爆炸对象,比如根对象。然后,您通过连接列表来组合这些产品(嵌套元组),并将外部产品与 this 应用。
  • 老实说,我不明白是什么阻止您使用链接页面中投票最高的答案。 product 返回一个迭代器,您可以将其发送到函数并返回生成的生成器,如 return flatten(product(...))
  • 谢谢@vaultah,我明白了,但我确实尝试了那个函数,而且它使用递归,我不想要这里,它产生整数和其他原语,而不是像原始结构那样的元组。而且我需要挂钩和处理该迭代器,因为我希望客户端接收相同的元组,它们代表分解的数据,而不是它们的内容流,它有几行。无论如何,我用过那个,但它不起作用,我得到的只是几十个单独的整数或字符串,没有行。我不能依赖客户端再次创建元组或列表。
  • 是的,也许我不能,但我想试试。我已经滥用了爆炸引擎的递归,所以我现在想避免,因为我担心性能和内存使用量的峰值。谢谢@Natecat。

标签: python tuples generator stdtuple


【解决方案1】:
def gen(data):
   for item in data:
      if isinstance(item, tuple):
          for nested in gen(item):
              yield nested
      else:
          yield item

未经测试,但应该可以工作。

【讨论】:

  • 不,但谢谢。请记住, itertools.product() 将元组作为不同的组合返回,我确实想要这些组合,只是没有内部元组。有了这个,我得到的只是几十个独立的整数或字符串,没有组合的界限。
  • @rsalmei 所以你是说你不想要发电机?
  • 不,我想要一台发电机!这就是我所要求的:列表理解或生成器表达式......我只需要删除内部元组,而不是组合。
  • @rsalmei 什么?里面没有产品......它几乎是递归。
【解决方案2】:

这并不容易,必须使用递归,但要与主要的__iter__ 方法分开。我就是这样结束的。 现在还有一个递归生成器_merge,由另一个生成器_flatten调用:

class Explosion:
    # ...

    def __iter__(self):
        def _flatten(container):
            def _merge(t):
                for te in t:
                    if isinstance(te, tuple):
                        for ite in _merge(te):
                            yield ite
                    else:
                        yield te

            for t in container:
                yield tuple(_merge(t))

        return _flatten(product(*self.fragments))

查看_flatten() 函数的使用示例:

>>> list(itertools.product([1,2],[3,(4,(5,6))]))
[(1, 3), (1, (4, (5, 6))), (2, 3), (2, (4, (5, 6)))]
>>> list(_flatten(itertools.product([1,2],[3,(4,(5,6))])))
[(1, 3), (1, 4, 5, 6), (2, 3), (2, 4, 5, 6)]

【讨论】:

  • 如果您愿意,您还可以将_flatten 辅助方法嵌套在您的__iter__ 方法,以防您在其他任何地方都不需要它。
  • @ByteCommander,我尝试将 merge 辅助方法作为第二个生成器,在 _flatten 生成器中,但它不起作用,外部元组(我想要维护的那些)空出来的。你知道为什么吗?我宁愿不使用临时序列来移动大量数据,但是......
  • 如果没有看到您的代码,我无法对此发表评论。提出一个新问题,并在此处的评论中给我一个链接。
  • 我做到了!!!问题是一个递归生成器,它需要一个封闭的 for 循环!查看我的更新答案@ByteCommander...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-01
  • 2021-12-06
  • 2011-07-23
  • 1970-01-01
  • 2015-08-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多