Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/eclipse/9.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 对于数字列表,查找其累积和在范围内的所有组合_Python_Combinations_Permutation_Combinatorics - Fatal编程技术网

Python 对于数字列表,查找其累积和在范围内的所有组合

Python 对于数字列表,查找其累积和在范围内的所有组合,python,combinations,permutation,combinatorics,Python,Combinations,Permutation,Combinatorics,假设我有以下列表: [A,A,A,A,B,B] 其中A=1,B=-1 查找此列表的所有组合通常很容易(8nCr3),但我想在累积和达到某些界限值(例如0和4)时忽略排列 因此,上面的例子是不正确的,因为累积总和是 [1,2,3,4,5,4,3,2]。 排列[A,A,B,B,A,A,B,A]也不好,因为这里的累积和是[1,2,1,0,1,2,1,2] 我的问题是:如何计算两个组件的有限列表的排列数 如果存在一个简单插入解析解的函数,我会非常高兴,但迭代/递归函数也可以 编辑:我其实不需要知道排列

假设我有以下列表:
[A,A,A,A,B,B]
其中
A=1,B=-1

查找此列表的所有组合通常很容易(8nCr3),但我想在累积和达到某些界限值(例如0和4)时忽略排列

因此,上面的例子是不正确的,因为累积总和是 [1,2,3,454,3,2]。

排列
[A,A,B,B,A,A,B,A]
也不好,因为这里的累积和是[1,2,1,0,1,2,1,2]

我的问题是:如何计算两个组件的有限列表的排列数

如果存在一个简单插入解析解的函数,我会非常高兴,但迭代/递归函数也可以


编辑:我其实不需要知道排列是什么样的。只要它们的数量就足够了。

一个可能的解决方案是使用
itertools.permutations
生成置换,然后检查每个置换

这种方法存在一些问题:

  • 无效排列的数量可能很大,因此我们将免费生成许多排列
  • 如果一个排列的第一项超出了界限,我们知道所有具有相同开头的排列都是无效的,但是没有办法使
    itertools。排列
    跳过它们,因此我们无论如何都必须生成它们
  • 我们必须重新计算每个新排列的所有部分和
因此,我们可以构建排列并在每一步测试它们。这样,一旦一个项目使我们越界,我们就可以中止整个分支

递归解决方案:

 def bounded_permutations(data, lower, upper, start=None, curr_sum=0):
    if start is None:
        start = []
        
    for idx_first, first in enumerate(data):
        new_sum = curr_sum + first
        if not lower < new_sum < upper:
            continue
        new_data = data[:]
        del new_data[idx_first]
        new_start = start + [first]
        if not new_data:  # we used all values in the list!
            yield new_start
        else:
            yield from bounded_permutations(new_data, lower, upper, new_start, new_sum)
输出:

[1, 1, 1, -1, 1, -1, -1] 1
[1, 1, 1, -1, 1, -1, -1] 2
[1, 1, 1, -1, -1, 1, -1] 3
[1, 1, 1, -1, -1, 1, -1] 4
[1, 1, 1, -1, 1, -1, -1] 5
.
.
.
[1, 1, -1, 1, -1, 1, -1] 575
[1, 1, -1, 1, -1, 1, -1] 576
{(1, 1, -1, 1, 1, -1, -1), 
 (1, 1, -1, 1, -1, 1, -1),
 (1, 1, 1, -1, 1, -1, -1),
 (1, 1, 1, -1, -1, 1, -1)}
number of unique permutations: 4
(1, 1, 1, -1, -1, 1, -1)
(1, 1, -1, 1, -1, 1, -1)
(1, 1, -1, 1, 1, -1, -1)
(1, 1, 1, -1, 1, -1, -1)
在这里,我们得到了576个有效排列,总共7个!=5040我们也可以用
len(列表(有界排列(数据,0,4))
来计算它们

由于数据中存在重复的值,您将得到许多相同的排列。如果只想保留唯一的,可以使用
。请注意,您必须将不可破坏列表转换为可哈希元组,才能在集合中使用它们:

uniques = set(map(tuple, bounded_permutations(data, 0, 4)))
print(uniques)
print('number of unique permutations:', len(uniques))
输出:

[1, 1, 1, -1, 1, -1, -1] 1
[1, 1, 1, -1, 1, -1, -1] 2
[1, 1, 1, -1, -1, 1, -1] 3
[1, 1, 1, -1, -1, 1, -1] 4
[1, 1, 1, -1, 1, -1, -1] 5
.
.
.
[1, 1, -1, 1, -1, 1, -1] 575
[1, 1, -1, 1, -1, 1, -1] 576
{(1, 1, -1, 1, 1, -1, -1), 
 (1, 1, -1, 1, -1, 1, -1),
 (1, 1, 1, -1, 1, -1, -1),
 (1, 1, 1, -1, -1, 1, -1)}
number of unique permutations: 4
(1, 1, 1, -1, -1, 1, -1)
(1, 1, -1, 1, -1, 1, -1)
(1, 1, -1, 1, 1, -1, -1)
(1, 1, 1, -1, 1, -1, -1)

您可以使用
itertools
生成排列和累积列表。返回其累积列表不包含某些特定值的唯一置换的紧凑解决方案是:

import itertools

def contain_specific_value(lst, value_lst):
    return any([True if (item in lst) else False for item in value_lst])

def accumulated_permutations_without_specific_numbers(main_lst, specific_number_lst):
    p = list(itertools.permutations(main_lst, len(main_lst)))
    res = [y for y in p if not contain_specific_value(list(itertools.accumulate(y)), specific_number_lst)]
    return list(set(res))
您只需要将某些绑定值作为列表传递给函数

对于您的列表:

A=1
B=-1
my_list = [A, A, A, A, B, B, B]

res = accumulated_permutations_without_specific_numbers(my_list, [0,4])
输出:

[1, 1, 1, -1, 1, -1, -1] 1
[1, 1, 1, -1, 1, -1, -1] 2
[1, 1, 1, -1, -1, 1, -1] 3
[1, 1, 1, -1, -1, 1, -1] 4
[1, 1, 1, -1, 1, -1, -1] 5
.
.
.
[1, 1, -1, 1, -1, 1, -1] 575
[1, 1, -1, 1, -1, 1, -1] 576
{(1, 1, -1, 1, 1, -1, -1), 
 (1, 1, -1, 1, -1, 1, -1),
 (1, 1, 1, -1, 1, -1, -1),
 (1, 1, 1, -1, -1, 1, -1)}
number of unique permutations: 4
(1, 1, 1, -1, -1, 1, -1)
(1, 1, -1, 1, -1, 1, -1)
(1, 1, -1, 1, 1, -1, -1)
(1, 1, 1, -1, 1, -1, -1)
累计名单:

[1, 2, 3, 2, 1, 2, 1]
[1, 2, 1, 2, 1, 2, 1]
[1, 2, 1, 2, 3, 2, 1]
[1, 2, 3, 2, 3, 2, 1]

下面是一个使用动态规划(记忆)的递归解决方案,以便即时处理非常大的列表:

from functools import lru_cache

def boundCumSum(A,loBound,hiBound):
    sRange = range(loBound+1,hiBound)
    
    @lru_cache()
    def count(s,nPos,nNeg):
        if nPos==0 and nNeg==0: return int(s == 0)
        if nPos<0 or nNeg<0 or not s in sRange: return 0
        return count(s-1,nPos-1,nNeg)+count(s+1,nPos,nNeg-1)
    
    nPos   = sum(a>0 for a in A)
    nNeg   = sum(a<0 for a in A)
    return count(sum(A),nPos,nNeg)
为了验证这一点,可以使用生成器函数来显示实际解及其累积和:

def genCumSum(A,loBound,hiBound,combo=[]):
    if not A: yield combo; return
    for v,i in {v:i for i,v in enumerate(A)}.items():
        if v<=loBound or v >=hiBound: continue
        yield from genCumSum(A[:i]+A[i+1:],loBound-v,hiBound-v,combo+[v])


到目前为止你都试了些什么?非常感谢。我相信它是有效的,但是如果我将列表大小增加到20年代的某个地方,这个函数将花费很长时间。是的,当然,20个元素的排列数是20!=2432902008176640000,约为2.4*10^18。如果你能每秒生成10^6个排列,那么需要77147年才能生成所有排列,而且你无法存储它们。这个解决方案可以避免生成我们确信会失败的解决方案,也可以避免生成许多解决方案,但根据值和边界,解决方案的数量可能会很大。作为旁注,如果你觉得其中一个答案回答了你的问题,你可以接受它(左边的复选标记)和/或投赞成票。就像Thierry Lathuille的答案一样,我认为这个函数对于相当小的列表来说已经花费了很长时间。但你的回答很有见地,谢谢。