Flattening irregular Python multidimensional arrays to one dimension, have you lost your studies?

Preface

The text and pictures in this article are from the Internet and are for learning and communication purposes only. They do not have any commercial use. If you have any questions, please contact us for processing.

PS: If you need Python learning materials, you can click on the link below to get it yourself

Python free learning materials and group communication answers Click to join


A group of friends made a request before:

 

For example, there is a list:

l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Hope to convert it into the following form:

[1, 2, 3, 4, 5, 6, 7, 8, 9] The
group of friends also enthusiastically gave their opinions and plans:

 

 

I feel very good, but there is actually an easier way.

In addition, if it is the following irregular multidimensional list:

l = [[1, 2], [3, 4], [5, [6, 7, [8, 9]]], 10, [11, [12, 13, [14, 15, [16]]]]]

We want to flatten it to a one-dimensional list:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

Conventional methods will not work well. I will teach you how to implement depth-first traversal strategies through recursion or stacks to solve this problem.

 

Use numpy to flatten an array

import numpy as np

np.array(l).flatten().tolist()

result:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

Use python to flatten an array

Using numpy arrays to flatten the array is actually very limited. Once the length of each element in the list is inconsistent, numpy is not easy to use:

l = [[1, 2, 3], [4, 5], [6, 7], [8, 9, 10, 11]]
np.array(l).flatten().tolist()

D:\Anaconda3\lib\site-packages\ipykernel_launcher.py:2: VisibleDeprecationWarning: Creating an ndarray fr
结果:

[[1, 2, 3], [4, 5], [6, 7], [8, 9, 10, 11]]
At this time, we can implement the leveling operation through the chain of the python itertools library:

import itertools

list(itertools.chain(*l))

result:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Of course, there is a more advanced method of operation is to use the sum function directly:

sum(l, [])

result:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
You may be confused. Why can the sum function achieve list flattening? Let me translate what this code actually does:

result = []
for i in l:
    result += i
result

result:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
The first parameter of sum(l, []) is the container to be iterated, and the second element is an initial value. Its working mechanism is the same as the reduce idea of ​​functional programming. It uses an initial value to continuously iterate each element of the target into the initial object.

Flatten irregular multidimensional array to 1 dimension

The above requirements seem very simple. What if we want to flatten the following complex list to one dimension?

l = [[1, 2], [3, 4], [5, [6, 7, [8, 9]]], 10, [11, [12, 13, [14, 15, [16]]]]]

With such an irregular list, the above methods are no longer good. What should I do at this time?

When this list is not long, we can play some tricks:

list_str = str(l).replace("[", "").replace("]", "")
eval(f"[{list_str}]")

result:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] The
principle is to first convert this list into ordinary strings, and then all After removing all [] characters and converting them into a single-dimensional list of string form, use the eval function for analysis.

For the string replacement above, it would be better to use regular replacement:

import re

eval(re.sub("(?!^)\[|\](?!$)", "", str(l)))

result:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
This little trick is very clever, but the length of this irregular list is long enough, the elements When enough, this method may be unacceptable in performance, because parsing strings to create objects has a large resource overhead.

Depth-first traversal strategy to flatten multi-dimensional arrays

Below I introduce a normal way to solve this problem, that is to use the depth-first traversal strategy. If you have no order requirements for the flattened results, you can also use the breadth-first traversal strategy.

The simplest and most straightforward idea of ​​the depth-first traversal strategy is to use recursion:

def flatten(items, result=[]):
    for item in items:
        if isinstance(item, list):
            flatten(item, result)
        else:
            result.append(item)


result = []
flatten(l, result)
result

result:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
Although recursion may have too many call stacks, which may cause performance degradation or program hangs, Python can use generators to turn recursive calls into ordinary calls:

def flatten(items):
    for item in items:
        if isinstance(item, list):
            yield from flatten(item)
        else:
            yield item


result = [e for e in flatten(l)]
result

result:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
If we don’t want to use recursion or generators to implement depth-first traversal, we can also use A stack to achieve depth-first traversal.

In order to ensure that the result is the original order, we use the left end as the top of the stack, and the array is not suitable for deleting the data at the left end, so we use deque as the stack.

First, we need to convert the original list to deque. Here is the processing code:

from collections import deque

stack = deque(l)
result = []
while len(stack) != 0:
    item = stack.popleft()
    if isinstance(item, list):
        for e in reversed(item):
            stack.appendleft(e)
    else:
        result.append(item)
result

result:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
If we regard the original list as a stack with the top of the stack at the right end, we can pass to Insert data at the left end of the result to maintain the original order:

from collections import deque

stack = l.copy()
result = deque()
while len(stack) != 0:
    item = stack.pop()
    if isinstance(item, list):
        for e in item:
            stack.append(e)
    else:
        result.appendleft(item)
result = list(result)
result

result:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

summary

Unexpectedly, the small list is flattened and there is so much knowledge. I hope today’s sharing can help you learn

Guess you like

Origin blog.csdn.net/pythonxuexi123/article/details/112987226