Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Python';s itertools.排列是否包含重复项?(当原始列表有重复项时)_Python_Algorithm_Language Design_Permutation - Fatal编程技术网

为什么Python';s itertools.排列是否包含重复项?(当原始列表有重复项时)

为什么Python';s itertools.排列是否包含重复项?(当原始列表有重复项时),python,algorithm,language-design,permutation,Python,Algorithm,Language Design,Permutation,人们普遍认为n个不同符号的列表有n个!排列。然而,当符号不明显时,在数学和其他领域,最常见的惯例似乎是只计算不同的排列。因此,列表[1,1,2]的排列通常被认为是 [1,1,2],[1,2,1],[2,1,1]。实际上,下面的C++代码精确地打印了三个: inta[]={1,1,2}; 做{ 库特这么说: 元素根据其位置而不是其值被视为唯一的 我的问题:为什么要做出这个设计决定 似乎遵循通常的约定会得到更有用的结果(事实上,这正是我想要的)……或者我缺少Python行为的一些应用程序 (例如,在

人们普遍认为n个不同符号的列表有n个!排列。然而,当符号不明显时,在数学和其他领域,最常见的惯例似乎是只计算不同的排列。因此,列表
[1,1,2]
的排列通常被认为是
[1,1,2],[1,2,1],[2,1,1]
。实际上,下面的C++代码精确地打印了三个:

inta[]={1,1,2};
做{
库特这么说:

元素根据其位置而不是其值被视为唯一的

我的问题:为什么要做出这个设计决定

似乎遵循通常的约定会得到更有用的结果(事实上,这正是我想要的)……或者我缺少Python行为的一些应用程序


(例如,在代码< NExtx置换> <代码>中的算法——例如在StAdvExcel上解释的-在Python中似乎是有效的和可实现的,但是Python做一些更有效的事情,因为它不能保证基于值的字典顺序吗?如果是这样,效率的提高会被考虑吗?ed值得吗?]

也许我错了,但原因似乎就在这里 您已经指定了(1,1,2),并且从您的角度来看,0索引处的1和1索引处的1是相同的-但是这不是如此,因为置换python实现使用索引而不是值

因此,如果我们看一下默认的python置换实现,就会发现它使用索引:

def permutations(iterable, r=None):
    pool = tuple(iterable)
    n = len(pool)
    r = n if r is None else r
    for indices in product(range(n), repeat=r):
        if len(set(indices)) == r:
            yield tuple(pool[i] for i in indices)

例如,如果您将输入更改为[1,2,3],您将得到正确的排列([(1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1,2),(3,2,1)])由于值是唯一的。

通过包装
itertools.permutations
,很容易获得您喜欢的行为,这可能会影响决策。如文档中所述,
itertools
被设计为构建自己的迭代器时使用的构建块/工具的集合

def unique(iterable):
    seen = set()
    for x in iterable:
        if x in seen:
            continue
        seen.add(x)
        yield x

for a in unique(permutations([1, 1, 2])):
    print a

(1, 1, 2)
(1, 2, 1)
(2, 1, 1)
但是,正如评论中指出的,这可能没有您希望的那么有效:

>>> %timeit iterate(permutations([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2]))
1 loops, best of 3: 4.27 s per loop

>>> %timeit iterate(unique(permutations([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2])))
1 loops, best of 3: 13.2 s per loop

也许如果有足够的兴趣,可以在
itertools.permutations
中添加一个新函数或可选参数,以更有效地生成没有重复的置换。

我不能代表
itertools.permutations
的设计者说话(雷蒙德·赫廷格),但在我看来,这项设计有两点可取之处:

首先,如果您使用
next\u permutation
风格的方法,那么您将被限制为传入支持线性排序的对象。而
itertools.permutations
提供任何类型的对象的置换。想象一下这将是多么烦人:

>>> list(itertools.permutations([1+2j, 1-2j, 2+j, 2-j]))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: no ordering relation is defined for complex numbers
>列表(itertools.置换([1+2j,1-2j,2+j,2-j]))
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:没有为复数定义排序关系
第二,通过不测试对象上的相等性,
itertools.permutations
避免了在通常情况下调用
\uuuuuuueq\uuuu
方法的成本,而这种方法在通常情况下是不必要的


基本上,
itertools.permutations
以可靠且廉价的方式解决了常见问题。当然有一个论点认为
itertools
应该提供一个避免重复置换的函数,但这样一个函数应该是对
itertools.permutations
的补充,而不是取而代之。为什么不编写这样一个函数呢函数并提交补丁?

我接受Gareth Rees的回答,认为这是最吸引人的解释(Python库设计者的回答不多)也就是说,Python的
itertools.permutations
不会比较元素的值。想想看,这就是问题所要问的,但我现在明白了它是如何被视为一种优势的,这取决于人们通常使用
itertools.permutations

为了完整起见,我比较了三种生成所有不同排列的方法。方法1在内存和时间方面效率都很低,但需要的新代码最少,它是包装Python的
itertools.permutations
,如zeekay的答案所示。方法2是基于生成器的C++的
下一个排列
,来自.Method 3是我写的更接近的方法;它修改了列表(我没有把它做得太笼统)

def next_排列(l):
n=len(l)
#第一步:找到尾巴
last=n-1#尾巴从“last”到结尾
当上次>0时:
如果l[last-1]0:
小=l[最后一个-1]
大=n-1
而我[大]0
下面是一些结果。我现在更加尊重Python的内置函数:当元素全部(或几乎全部)不同时,它的速度大约是其他方法的三到四倍。当然,当有许多重复元素时,使用它是一个糟糕的主意

Some results ("us" means microseconds):

l                                       m_itertoolsp  m_nextperm_b  m_nextperm_s
[1, 1, 2]                               5.98 us       12.3 us       7.54 us
[1, 2, 3, 4, 5, 6]                      0.63 ms       2.69 ms       1.77 ms
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]         6.93 s        13.68 s       8.75 s

[1, 2, 3, 4, 6, 6, 6]                   3.12 ms       3.34 ms       2.19 ms
[1, 2, 2, 2, 2, 3, 3, 3, 3, 3]          2400 ms       5.87 ms       3.63 ms
[1, 1, 1, 1, 1, 1, 1, 1, 1, 2]          2320000 us    89.9 us       51.5 us
[1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4]    429000 ms     361 ms        228 ms

代码是任何人都想探索的。

我发现同样令人惊讶的是,
itertools
没有更直观的唯一排列概念。对于任何严肃的应用程序,生成重复排列只是为了选择其中的唯一排列是不可能的

我已经编写了自己的迭代生成器函数,其行为类似于
itertools。排列
,但不返回重复项。仅考虑原始列表的排列,可以使用标准
itertools
库创建子列表

def unique_permutations(t):
    lt = list(t)
    lnt = len(lt)
    if lnt == 1:
        yield lt
    st = set(t)
    for d in st:
        lt.remove(d)
        for perm in unique_permutations(lt):
            yield [d]+perm
        lt.append(d)

回顾这个老问题,现在最简单的方法就是使用。

根据Python,它确实保证了字典顺序。上面的输出示例没有看到
def unique_permutations(t):
    lt = list(t)
    lnt = len(lt)
    if lnt == 1:
        yield lt
    st = set(t)
    for d in st:
        lt.remove(d)
        for perm in unique_permutations(lt):
            yield [d]+perm
        lt.append(d)