Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unnest (unlevel) unnecessary nested list without changing its shape? (Python)

This is quite different what I found in many threads - I don't mean to make list flat but unnest levels as follows:

[[[3, 3]]] should be [3, 3]

[[[3, 4], [3, 3]]] should be [[3, 4], [3, 3]] but not [3, 4], [3, 3] nor [3, 4, 3, 3] because this changes the structure completely.

Basically, I wanted to reduce levels to get the same len(a_list) in first and second iteration before loop break. But my idea is somewhat wrong:

This code works for anything but [[3], [4]]. Dunno what's wrong today because it worked yesterday. Need some help to correct this function. Now it returns [3] but should be unchanged.

# Unlevel list - reduce unnecessary nesting without changing nested lists structure
def unlevelList(l):
    if len(l) > 0 and isinstance(l, list):
        done = True
        while done == True:
            if isinstance(l[0], list):
                if len(l) == len(l[0]):
                    l = l[0]
                else:
                    l = l[0]
                    done = False
            else:
                done = False
        return l
    else:
        return l
like image 932
Peter.k Avatar asked Mar 06 '26 07:03

Peter.k


2 Answers

I'd be inclined to do this with recursion: if the object is a list of length 1, strip off the outer layer; then, recursively unlevel all of its children.

def unlevel(obj):
    while isinstance(obj, list) and len(obj) == 1:
        obj = obj[0]
    if isinstance(obj, list):
        return [unlevel(item) for item in obj]
    else:
        return obj

test_cases = [
    [[[3, 3]]],
    [[[3, 4], [3, 3]]],
    [[3], [4]],
    [[[3]]],
    [[[3], [3, 3]]]
]

for x in test_cases:
    print("When {} is unleveled, it becomes {}".format(x, unlevel(x)))

Result:

When [[[3, 3]]] is unleveled, it becomes [3, 3]
When [[[3, 4], [3, 3]]] is unleveled, it becomes [[3, 4], [3, 3]]
When [[3], [4]] is unleveled, it becomes [3, 4]
When [[[3]]] is unleveled, it becomes 3
When [[[3], [3, 3]]] is unleveled, it becomes [3, [3, 3]]

Edit: reading your question again, I think perhaps you want [[3], [4]] to remain [[3], [4]]. If that is the case, then I interpret the requirements to be "only strip off excess brackets from the top layer; leave inner one-element lists unaffected". In which case you don't need recursion. Just strip off the top list until you can't any more, then return it.

def unlevel(obj):
    while isinstance(obj, list) and len(obj) == 1:
        obj = obj[0]
    return obj

test_cases = [
    [[[3, 3]]],
    [[[3, 4], [3, 3]]],
    [[3], [4]],
    [[[3]]],
    [[[3], [3, 3]]]
]

for x in test_cases:
    print("When {} is unleveled, it becomes {}".format(x, unlevel(x)))

Result:

When [[[3, 3]]] is unleveled, it becomes [3, 3]
When [[[3, 4], [3, 3]]] is unleveled, it becomes [[3, 4], [3, 3]]
When [[3], [4]] is unleveled, it becomes [[3], [4]]
When [[[3]]] is unleveled, it becomes 3
When [[[3], [3, 3]]] is unleveled, it becomes [[3], [3, 3]]
like image 86
Kevin Avatar answered Mar 07 '26 20:03

Kevin


Id recommend a recursive solution as well

def unnest(l):
    if isinstance(l, list) and len(l) == 1 and isinstance(l[0], list):
        return unnest(l[0])
    return l

Some test cases

test_cases = [
    [[[3], [3, 3]]],
    [[[3, 3]]],
    [[[3, 4], [3, 3]]],
    [[3], [4]],
    [[[3]]]
]

for i in test_cases:
    print(unnest(i))

gives

[[3], [3, 3]]
[3, 3]
[[3, 4], [3, 3]]
[[3], [4]]
[3]
like image 36
nathan.medz Avatar answered Mar 07 '26 22:03

nathan.medz