[英]Python - Create a hierarchy based on a flat list of values that add up to 100
I have a list (an OrderedDict, technically), that I need as a hierarchy based on the values that consecutively add up to 100. For example:我有一个列表(从技术上讲是 OrderedDict),我需要它作为基于连续加起来为 100 的值的层次结构。例如:
>>> a = OrderedDict([('1', 60), ('2', 15), ('3', 50), ('4', 40), ('5', 10), ('6', 85), ('7', 40)])
>>> a
OrderedDict([('1', 60),
('2', 15),
('3', 50),
('4', 40),
('5', 10),
('6', 85),
('7', 40)])
I want to create a hierarchy like this:我想创建一个这样的层次结构:
'1': [
'2': ['3', '4', '5'],
'6': []
],
'7': []
where 1 + 7 add up to 100, 2 + 6 add up to 100, and 3 + 4 + 5 add up to 100. Values can be repeated;其中 1 + 7 加起来是 100,2 + 6 加起来是 100,3 + 4 + 5 加起来是 100。值可以重复; for example, at worst it could look like:
例如,在最坏的情况下,它可能看起来像:
OrderedDict([('1', 50),
('2', 50),
('3', 50),
('4', 50)])
At which point, any guess will do;到那时,任何猜测都可以; this is overall unlikely.
这总体上不太可能。
I figured it's a relatively straightforward recursive function, but I can't figure out where to restart.我认为这是一个相对简单的递归 function,但我不知道从哪里重新开始。 I tried this:
我试过这个:
keys = list(a.keys())
l = []
c = 0
full = {}
def get_split_vars(full, curr_keys):
l = []
c = 0
for i in range(0, len(curr_keys)):
if c + a[curr_keys[i]] < 100: # if less than 100, keep trying
c += a[curr_keys[i]]
l.append(curr_keys[i])
elif c + a[curr_keys[i]] > 100: # if more than 100, reset
c = a[curr_keys[i]]
l = [curr_keys[i]]
elif c + a[curr_keys[i]] == 100: # if 100, this is a grouping, take it out of the full set
l.append(curr_keys[i])
full[curr_keys[i - len(l)]] = l
new_keys = [curr_keys[x] for x in range(0, len(curr_keys)) if curr_keys[x] not in l]
return full, new_keys
while keys:
full, keys = get_split_vars(full, keys)
which, as expected, gets the middle grouping (3, 4, and 5), but chokes at the smaller grouping - where it resets to '6' (85), rather than what I'd actually want ('2').正如预期的那样,它获得了中间分组(3、4和5),但在较小的分组中阻塞 - 它重置为“6”(85),而不是我真正想要的(“2”)。 I can't figure out where to modify the function, but it seems like I'm missing something simple.
我不知道在哪里修改 function,但似乎我缺少一些简单的东西。 Thanks in advance!
提前致谢!
Here's my extremely inelegant solution;这是我非常不雅的解决方案; critique welcome as I try to refactor:
在我尝试重构时欢迎批评:
keys = list(a.keys())
full = {}
last_var = ''
def get_split_vars(full, curr_keys, dct):
global last_var
l = []
c = 0
if len(curr_keys) < 3: # doubt that I'll see more than 4 possible 100% splits, but technically a limitation
already_included = False
print('2 left: ', curr_keys)
for val in curr_keys:
if val in full.keys():
already_included = True
if not already_included:
total = 0
for i3 in range(0, len(curr_keys)):
total += dct[curr_keys[i3]]
if total == 100:
full[last_var] = curr_keys
return full, []
for i in range(0, len(curr_keys)):
c = dct[curr_keys[i]]
l.append(curr_keys[i])
print('Start: ', i, c, l)
for i2 in range(i, len(curr_keys)):
if i == i2:
continue
c += dct[curr_keys[i2]]
l.append(curr_keys[i2])
if c < 100:
print('Added: ', i2, c, l)
elif c > 100:
print('Deleted: ', i2, c, l)
c = 0
l = []
break
elif c == 100:
print('Found: ', i2, c, l)
if i2 - len(l) < 0:
full['0'] = l
else:
full[curr_keys[i2 - len(l)]] = l
print(full)
last_var = l[-1]
new_keys = [curr_keys[x] for x in range(0, len(curr_keys)) if curr_keys[x] not in l]
l = []
c = 0
return full, new_keys
while keys:
full, keys = get_split_vars(full, keys, a)
which technically works:在技术上有效:
full_a full_a
{'2': ['3', '4', '5'], '1': ['2', '6'], '0': ['1', '7']}
and和
b = OrderedDict([('1', 80), ('2', 20), ('3', 75), ('4', 25)])
full_b full_b
{'0': ['1', '2'], '2': ['3', '4']}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.