【问题标题】:Generate from generators从生成器生成
【发布时间】:2013-09-03 06:51:34
【问题描述】:

我有一个生成器,它接受一个数字作为参数并产生其他数字。 我想使用这个生成器产生的数字并将它们作为参数传递给同一个生成器,创建一个一定长度的链。

例如,mygenerator(2) 产生 5、4 和 6。将 mygenerator 应用于这些数字中的每一个,一遍又一遍地应用于产生的数字。生成器总是产生比作为参数传递的更大的数字,并且对于 2 个不同的数字永远不会产生相同的数字。

mygenerator(2): 4 5 我的发电机(4):10 11 12 我的发电机(5):9 300 500

所以集合 (9,10,11,12,300,500) 与原始数字 2 的“距离”为 2。如果我将它应用于数字 9,我将得到一组距离为“3”的数字原创 2.

基本上我想要的是创建一个与给定数字具有指定距离的集合,但我在弄清楚如何在 Python 中做到这一点时遇到了问题。非常感谢帮助:)

【问题讨论】:

    标签: python generator


    【解决方案1】:

    假设我们的生成器生成给定数字的正方形和立方体,这样它将输出唯一的 因此,如果我们想在最简单的情况下获取 dist D 处的数字,我们可以递归地获取 dist D-1 处的数字,然后将生成器应用于它们

    def mygen(N):
        yield N**2
        yield N**3
    
    def getSet(N, dist):
        if dist == 0:
            return [N]
    
        numbers = []
        for n in getSet(N, dist-1):
            numbers += list(mygen(n))
    
        return numbers
    
    print getSet(2,0)
    print getSet(2,1)
    print getSet(2,2)
    print getSet(2,3)
    

    输出是

    [2]
    [4, 8]
    [16, 64, 64, 512]
    [256, 4096, 4096, 262144, 4096, 262144, 262144, 134217728]
    

    【讨论】:

      【解决方案2】:

      此解决方案不需要将所有结果保存在内存中:(以防它不适合内存等)

      def grandKids(generation, kidsFunc, val):
        layer = [val]
        for i in xrange(generation):
          layer = itertools.chain.from_iterable(itertools.imap(kidsFunc, layer))
        return layer
      

      例子:

      def kids(x): # children indices in a 1-based binary heap
        yield x*2
        yield x*2+1
      
      >>> list(grandKids(3, kids, 2))
      [16, 17, 18, 19, 20, 21, 22, 23]
      

      顺便说一句,Haskell 中的解决方案:

      grandKids generation kidsFunc val =
        iterate (concatMap kidsFunc) [val] !! generation
      

      【讨论】:

      • 对于这类问题,显然 Python 永远不会像 Haskell 那样简洁,但你至少可以通过依赖 itertools.chain 来节省 concat 辅助函数。
      • @John Y:itertools.chain 不会工作(很好)。 concat(xs) 将类似于链(*xs)。这会将 xs 评估为一个元组,因此会占用大量内存。
      • 这很有趣,但您在使用 Python 解决方案时有点作弊。如果我们编写您在 Python 中使用的 Haskell 的 Prelude 函数(这并不难),该函数看起来非常相似: def grandKids(generation, kidsFunc, val): return takeN(iterate(partial(concatMap, kidsFunc), [val] ),一代)不要误会我的意思,Haskell(和 FP)是纯粹的美,这里的寓意是我们可以在使用其他语言时受益于它的教训。完整代码:gist.github.com/406204
      • 其实不需要定义任何额外的函数,return reduce(lambda a, v: (x for v in a for x in kidsFunc(v)), xrange(generation), [val]) 是使用生成器表达式的grandKids 的一行代码。
      • @Lloeki:恕我直言,如果定义 concat 函数会更容易阅读。
      【解决方案3】:

      我刚开始学习 Python,如果我的回答看起来有点业余,请多多包涵。您可以做的是使用列表列表来填充从 myGenerator 函数返回的值。

      例如。以 2 作为起始参数,您的数据结构将类似于

      resDataSet = [[2], 
                    [4, 5],
                    [9, 10, 11, 12, 300 , 500]
                    ...
                   ]
      

      行索引应该为您提供距离,您可以使用像扩展这样的方法将更多数据添加到您的列表中。

      【讨论】:

        猜你喜欢
        • 2014-11-23
        • 2018-03-18
        • 1970-01-01
        • 2013-10-02
        • 1970-01-01
        • 2016-12-02
        • 1970-01-01
        • 2011-04-17
        • 1970-01-01
        相关资源
        最近更新 更多