简体   繁体   English

Python - 根据加起来为 100 的值的平面列表创建层次结构

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM