尽管此问题的变体在此站点上已被问过很多次,但我还没有找到有关如何对给定列表进行“有序组合”的任何信息。
首先,我不完全知道此函数的正确术语是什么,但是我将使用此列表:
list = [1,2,3,4,5,6,7,8,9,10]
我想找到的是此列表可以有多少种排序方式,所以
list[0] < list[1] < list[2] ... < list[len(list)-1]
(升序不重复)
但是
[list[0] + 1
不必等于list[1]
(选择哪个数字无关紧要,只要它们按升序排列并在列表中)]
并且,假设outList
是源自list
的合格列表
[len(outList)
不一定要与len(list)
相同-“合格”列表的长度不必与给定列表的长度相同,但不得更长。
一些符合这些规则的示例:
[1,4,5,9][2,6,7,8,9][1,2,4,8][8,10]
一些非示例:
[1,3,2,5,10][1,1,10][5,2,8,7,9]
数字不能重复,并且必须严格大于前一个数字。
我将如何实现这种功能?我对如何解决这个问题一无所知。我尝试使用for
循环,但似乎无法正常工作。
编辑:对不起,这个问题尚不清楚,如果仍然存在,因为我真的不知道该使用什么术语。我不知道如何正确地表达它,因此我添加了更多细节,下面是我的答案版本。显然,它没有优化。顺便说一句,AlexanderCécile,如果您查看我的历史,我曾经使用过js和jQuery(不是我不再使用了,但是我改变了方向),因此该函数遵循js的命名标准。
第二编辑:所有这些答案彼此都大相径庭,这表明了编码的美:)-尽管我的解决方案确实有效,但我的解决方案是非常基本的。这些命令在长度较大的列表(例如[1,2,3,4 ... 100,101])上运行更快吗?
您可以使用formula to calculate the number of combinations进行数学计算。
import math
def binomial_coeff(n, k):
return math.factorial(n) // (math.factorial(k) * math.factorial(n - k))
def num_all_combinations(lst_len):
return sum(binomial_coeff(lst_len, i) for i in range(lst_len))
list1 = list(range(10))
print(num_all_combinations(len(list1))) # prints 1023
binomial_coeff
函数使用组合公式(也称为二项式系数)来获取大小为n
且组大小为k
的列表的组合数量。然后,我们使用num_all_combinations
函数来获取所有组大小的组合数,并将它们加在一起。
您甚至可以使用@ kaya3建议的sums of binomial coefficients identity进一步简化此操作。这将导致以下代码:
list1 = list(range(10))
print(2**len(list1) - 1) # prints 1023
据我所知,您想知道有多少个不同的列表,其中某些元素的子集为lst
,并保持顺序。因为每个子集只能以一种顺序存在,所以答案就是number of subsets:2 ^ n,其中n是列表的长度。
def count_subsets(lst):
return 2 ** len(lst)
例如,如果列表为[1, 2, 3]
,则有2 ^ 3 = 8个有序子列表:
[]
[1]
[2]
[3]
[1, 2]
[1, 3]
[2, 3]
[1, 2, 3]
如果要排除空白列表和/或原始列表,则可以根据需要简单地执行2 ** len(lst) - 1
或max(0, 2 ** len(lst) - 2)
。当输入列表是为空时,max(0, ...)
处理特殊情况。
以上处理输入列表的元素完全不同时的情况,如您的示例。如果可能有重复的元素,则上面的公式会计数过多。为了解决这个问题,我们可以使用Counter查找每个元素的副本数。如果某个元素有k
个副本,则应该计算2 ** k
个包含0、1、2,...,k个副本的子列表,而不是k + 1
组合。
from collections import Counter
def count_subsets(lst):
r = 1
for k in Counter(lst).values():
r *= k + 1
return r
此解决方案很可能尚未优化,但我以某种方式想出了我想做的事情。有什么好方法可以改善这一点吗?
这似乎符合您的要求: