Python 返回累积和等于输入值的所有可能的键组合
对于inputPython 返回累积和等于输入值的所有可能的键组合,python,dictionary,Python,Dictionary,对于inputdata={“a”:1,“b”:1,“c”:3},我想获得如下的dict {1:[[“a”],[“b”], 2:[“a”,“b”], 3:[“c”], 4:[“a”,“c”],[“b”,“c”], 5:[“a”、“b”、“c”]] 其中键是输入字典中所有可能值的累积和,对应值是所有键的列表,使累积和成为可能 这里的困难在于可能有多个解决方案来获得相同的累积和(上面的1就是一个例子)。现在我知道我能做到 {v:list(data.keys())[:idx+1]表示v,idx在zip
data={“a”:1,“b”:1,“c”:3}
,我想获得如下的dict
{1:[[“a”],[“b”],
2:[“a”,“b”],
3:[“c”],
4:[“a”,“c”],[“b”,“c”],
5:[“a”、“b”、“c”]]
其中键是输入字典中所有可能值的累积和,对应值是所有键的列表,使累积和成为可能
这里的困难在于可能有多个解决方案来获得相同的累积和(上面的1
就是一个例子)。现在我知道我能做到
{v:list(data.keys())[:idx+1]表示v,idx在zip中(np.cumsum(list(data.values())),range(len(data))}
但这种方法并没有给出我想要的完整解决方案。具体地说,对于输入数据
,我只能得到
{1:['a'],
2:[a'、[b'],
5:[a',b',c']}
当数据中存在更多重复项时,问题可能会变得更难解决
我想知道这个问题是否有好的解决方案(从我的计算理论课程来看,这个问题似乎是NP完全问题)。您可以使用递归生成器函数获取字典键的所有组合,并使用集合。defaultdict
根据它们产生的和对组合进行分组:
from collections import defaultdict
data = {"a": 1, "b": 1, "c": 3}
def to_sum(d, c = []):
if c:
yield c
if len(d) > len(c):
yield from [i for b in data for i in to_sum(d, c+[b]) if b not in c]
result = defaultdict(set)
for i in to_sum(data):
result[sum(data[j] for j in i)].add(tuple(sorted(i)))
final_result = {a:list(map(list, b)) for a, b in result.items()}
输出:
{1: [['b'], ['a']], 2: [['a', 'b']], 5: [['a', 'b', 'c']], 4: [['b', 'c'], ['a', 'c']], 3: [['c']]}
您的问题与数据的类型有关。具体来说,电源组不包括空组。我们可以使用标准库中的itertools
来帮助我们
from collections import defaultdict
from itertools import chain, combinations
def nonempty_powerset(data):
# adapted from the powerset recipe
# at https://docs.python.org/3/library/itertools.html
# start the range from 1 to exclude the empty set
return chain.from_iterable(combinations(data, r) for r in range(1, len(data) + 1))
def get_subset_sums(data):
output = defaultdict(list)
for subset in nonempty_powerset(data):
# subset is a tuple of strings, if you want lists we need to convert them
output[sum(data[item] for item in subset)].append(list(subset))
# convert to a regular dict
return dict(output)
print(get_subset_sums({"a": 1, "b": 1, "c": 3}))
运行时应该在O(N*2**N)
中,其中N=len(data)
,这对于涉及电源组的东西来说非常合理。也许我错过了一个numpy方法,它可以帮助您实现这一点,但除此之外,我认为这相当接近于最佳状态。您看过iTertools函数了吗?这个问题可能会有所帮助-我认为它的运行时间是O(N*log(N)*N**N)
其中N=len(data)
。