【问题标题】:Find all combinations of list elements including duplicate elements查找列表元素的所有组合,包括重复元素
【发布时间】:2018-05-08 18:17:49
【问题描述】:

我正在寻找一种在 python 中的算法,该算法将返回一个允许重复元素并加起来为某个数字的数字列表的所有可能组合...

例如,给定一个目标数 7,以及一个列表 [2, 3, 4],我希望能够生成以下组合:

2, 2, 3
2, 3, 2
3, 2, 2
3, 4
4, 3

我了解如何获取列表的所有可能组合,但我不知道如何以这种方式包含重复项。任何帮助将不胜感激!

【问题讨论】:

  • 你试过什么?你能提供任何代码吗?
  • 2,2,3 与 2,3,2 有何不同?它甚至不是一个排列
  • 音乐不一样。我是一名音乐家,正在寻找一种算法来提供酒吧中所有可能的节拍分组。

标签: python algorithm list


【解决方案1】:

您可以创建一个递归函数并应用必要的逻辑:

def combinations(d, current=[], sum_to = 7):
  if sum(current) == 7:
     yield current
  else:
    for i in d:
      if sum(current+[i]) <= 7:
         yield from combinations(d, current+[i])

print(list(combinations([2, 3, 4])))

输出:

[[2, 2, 3], [2, 3, 2], [3, 2, 2], [3, 4], [4, 3]]

【讨论】:

  • 投了反对票,因为这是从这里公然复制粘贴,只是更改了变量名 ---> stackoverflow.com/a/34519260/8746930
  • 不应该 print(list(filter(lambda x:sum(x) == 7, combination([1,2,3])))) 也产生 [1,1,1, 1,1,1,1]?
  • @eagle 我没有复制/粘贴,但是,两个答案的逻辑非常相似。
  • 受到@DirkHerrmann 评论的启发:为什么len(current) == len(d) 允许重复?
【解决方案2】:

这是一个蛮力解决方案:

def getAllSubsetsWithCertainSum(number_list, target_sum):

    matching_numbers = []

    def recursion(subset):
        for number in number_list:
            if sum(subset+[number]) < target_sum:
                recursion(subset+[number])
            elif sum(subset+[number]) == target_sum:
                matching_numbers.append(subset+[number])

    recursion([])
    return matching_numbers


print(
    getAllSubsetsWithCertainSum([2, 3, 4], 7)
)

如果你输入一个 1 它也会返回 [1, 1, 1, 1, 1, 1, 1]

【讨论】:

  • 这正是我想要的!简单又好用!
【解决方案3】:

之前答案的一个变体,有一个重要的区别:我们发现只有 sorted 的组合总和为目标,然后 然后 生成排列。 [2,3,4]7 的示例:

  • 第一步:找到[2,2,3][3,4]
  • 第 2 步:生成排列:[[2, 2, 3], [2, 3, 2], [3, 2, 2], [3, 4], [4, 3]]

这确实更快。这是代码(permute_unique 取自 here 并使用列表理解进行了优化):

def combinations2(d, sum_to):
    def combinations_aux(d, current, sum_to):
        for j in range(len(d)):
          nex = current+[d[j]]
          if sum(nex) == sum_to:
              yield nex
          elif sum(nex) < sum_to:
             yield from combinations_aux(d[j:], nex, sum_to) # d[j:] for elements >= d[j]

    def permute_unique(iterable):
        # see https://stackoverflow.com/a/39014159/6914441
        perms = [[]]
        for i in iterable:
            perms = [perm[:j] + [i] + perm[j:] 
                for perm in perms 
                for j in itertools.takewhile(lambda j:j<1 or perm[j-1] != i, range(len(perm) + 1))
            ]
        return perms

    return (p for c in combinations_aux(sorted(set(d)), [], sum_to) for p in permute_unique(c))

基准测试(来自 Ajax1234 的combinations):

def one(): return list(combinations([2,3,4,5,6,7], 35))
def two(): return list(combinations2([2,3,4,5,6,7], 35))

assert sorted([tuple(t) for t in one()]) == sorted([tuple(t) for t in two()]) 

print (timeit.timeit(one, number=10))
# 154.99560340600146
print (timeit.timeit(two, number=10))
# 23.217042586999014

【讨论】:

    猜你喜欢
    • 2012-04-11
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    相关资源
    最近更新 更多