列表的所有k-way分区的递归算法

时间:2013-10-14 03:43:40

标签: python recursion data-partitioning

我正在编写一个应该输出列表A的所有k-way分区的函数。 这个问题显然是递归的,实现应该是直截了当的:

def gen_partition_k_group( A, k):
    #
    if len(A) == 0 :
        # EDITED FOLLOWING SUGGESTION
        yield [ [] for _ in xrange(k) ]
    #
    else :
        # all k-partitions of the list of size N-1
        for ss in gen_partition_k_group(A[:-1], k) :
            assert( sum( len(gg) for gg in ss ) == len(A) -1 )
            for ii in xrange(k) :
                tt = list(ss)
                print tt
                tt[ ii ].append( A[ -1 ] )
                print tt
                assert( sum( len(gg) for gg in tt ) == len(A) )
                yield tt

A = range(3)
k = 2
[ xx for xx in gen_partition_k_group( A, k) ]

输出

  

AssertionError:

     

[[],[]]

     

[[0],[0]]

我不明白输出。它应该是[[0], []]而不是[[0], [0]]。我错过了什么?

注意:我知道如何在没有append的情况下编写不同的函数来输出正确的结果。 Iterator over all partitions into k groups?(第一个答案)

我不明白这个特定功能的行为。

2 个答案:

答案 0 :(得分:1)

一个问题可能是[ [] ] * k没有按照您的想法行事。这不会使k为空列表,它会创建一个新的空列表,并k引用它。例如:

>>> [[]]*3
[[], [], []]
>>> a = [[]]*3
>>> a
[[], [], []]
>>> a[0].append(1)
>>> a
[[1], [1], [1]]
>>> id(a[0]), id(a[1]), id(a[2])
(25245744, 25245744, 25245744)
>>> a[0] is a[1]
True
>>> a[0] is a[2]
True

要制作多个新列表,您可以执行类似

的操作
>>> a = [[] for _ in xrange(3)]
>>> a
[[], [], []]
>>> id(a[0]), id(a[1]), id(a[2])
(41563560, 41564064, 41563056)

我认为这本身不会修复你的程序 - 我仍然会得到assert绊倒 - 但它应该会有所帮助。

答案 1 :(得分:0)

好的问题是行tt = list(ss)只是列表的浅表副本。使用tt = copy.deepcopy(ss)解决了问题。