Two Python3 implementations of dynamic loops, indefinite layers of loops (recursive, pure loops)

'''
Two Python3 implementations of dynamic loops, indefinite layers of loops (recursive, pure loops)

# Note: Python only has list type by default, just understand it as an array of C.
# To take 3 elements from the following 3 arrays to form one, and print out the possible combinations
data = [
    [1, 2],
    [3, 4, 5],
    [6, 7, 8, 9]
]
# Means that there will be 2 * 3 * 4 = 24 possibilities, that is, the Deca product of all lists, the solution can be implemented with a triple loop for example:
for i in data[0]:
    for j in data[1]:
        for k in data[2]:
            print([i, j, k])

But if the number of arrays in data is uncertain, how to implement a dynamic indefinite layer loop?
I think of data as a two-dimensional array:
The first dimension is the number of data containing the array, that is, the Y axis, starting from 0 and increasing from line to line;
The second dimension is the number of elements contained in each array, that is, the X axis, starting from 0 and increasing column by column from left to right;
Then use recursive and pure loop to process the X and Y axes respectively.
'''

'''
Recursive method
From the first layer of the Y axis, index = 0, recursively from top to bottom, and when the bottom layer is reached, a loop is used to add one element of the bottom layer to the list to be returned.
Note: Python has a limit on the number of recursive layers, and different operating systems have different limits. It is necessary to consider another algorithm when it is above 100 layers.
'''
# data data source, cur_y_idx current Y-axis value, lst_rst return result list, lst_tmp is used to temporarily assemble elements of lst_rst
def dynloop_rcsn(data, cur_y_idx = 0, lst_rst = [], lst_tmp = []):
    max_y_idx = len (data)-1 # Get the maximum index value of Y axis
    for x_idx in range (len (data [cur_y_idx])): # traverse the X axis of the current layer
        lst_tmp.append (data [cur_y_idx] [x_idx]) # Append the elements of the X axis of the current layer to lst_tmp
        if cur_y_idx == max_y_idx: # If the current layer is the bottom layer, append lst_tmp as an element to lst_rst
            lst_rst.append([*lst_tmp])
        else: # If the current is not the bottom layer, the Y axis +1 continues to recursively, so the maximum number of recursive layers is the maximum value of the Y axis
               # The addresses of lst_rst and lst_tmp are also passed to the next recursion, so that the same list object is modified no matter which layer is modified
            dynloop_rcsn(data, cur_y_idx+1, lst_rst, lst_tmp)
        lst_tmp.pop () # At the end of this loop, whether it is recursively returned or the bottom loop, the last element of lst_tmp must be removed

    return lst_rst


'''
Round robin
The multilevel loop is 'flattened' into a one-level loop, that is, the Y axis has only 0, and only the X axis is traversed, and the 2-dimensional array becomes a 1-dimensional array.
The difficulty is that each loop must calculate the index of each extracted element to extract the elements in the original 2D array.
'''
def dynloop_loop(data):
    # Variable initialization
    max_y_idx = len (data) # Get the maximum value of the Y axis of the original 2D array
    row_max_idx = 1 # Record the maximum value of the X axis, the initial value is 1, the following calculation
    arr_len, lst_row, lst_rst = [], [], []
    arr_idx = [0] * max_y_idx # Save the set of index values ​​of max_y_idx elements extracted each time, the initial value is [0, 0, 0, 0]

    # Convert 2-dimensional array data to 1-dimensional array lst_row
    for item in data:
        _n = len (item) # Find the length of each layer in the original 2-dimensional array
        arr_len.append (_n) # Save the set of the length of each layer in the original 2D array
        lst_row + = item # accumulate each element of the original 2-dimensional array into the 1-dimensional array lst_row
        row_max_idx * = _n # record the total number of loops needed for a 1-dimensional array

    # Iterate over 1-dimensional array
    for row_idx in range(row_max_idx):
        # Find the index value of each extracted element
        for y_idx in range(max_y_idx):
            # Traverse the set of 'slices' of each layer length of the original 2D array, for example: lst = [1, 2, 3, 4]
            # Then lst [2:] is [3, 4], that is, everything starting from subscript 2; lst [: 2] is [1, 2], that is, before subscript 2
            # _pdt is the abbreviation of product, which records the product of the lengths of all layers below the current layer of the original 2D array
            _pdt = 1
            for n in arr_len[y_idx+1:]:
                _pdt * = n
            # _offset is the offset, recording the sum of the lengths of all layers above the current layer of the original 2D array
            _offset = 0
            for n in arr_len[:y_idx]:
                _offset += n
            # Calculate the element extraction index: divide the current X-axis value by _pdt, then take the remainder from the original 2D array current layer length, and add the offset
            arr_idx[y_idx] = (row_idx // _pdt) % arr_len[y_idx] + _offset

        # Traverse the index collection, select elements from the 1-dimensional array and put them in _lst_tmp
        _lst_tmp = []
        for idx in arr_idx:
            _lst_tmp.append(lst_row[idx])
        # Finally, append _lst_tmp as an element to lst_rst
        lst_rst.append(_lst_tmp)

    return lst_rst



'''
Relatively speaking, the recursive method is more convenient for code reading, and it is more in line with the intuition of thinking; the circular method is more circumvent but relatively unlimited by the number of recursive layers.
The following are the two methods for the same data test, you can see that the two lists returned have the same element.
'''
if __name__ == "__main__":

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

    print('----------------')
    lst1 = dynloop_loop(data)
    print(len(lst1))
    print(lst1)

    print('----------------')
    lst2 = dynloop_rcsn(data)
    print(len(lst2))
    print(lst2)

    print('----------------')
    # Return True if two lists have the same element
    print(lst1 == lst2)

 

import itertools
from dynloop_loop_rcsn import dynloop_loop, dynloop_rcsn


if __name__ == "__main__":

    data = [
        [1, 2],
        [3, 4, 5],
        [6, 7, 8, 9],
        [11, 12],
        [13, 14, 15],
        [16, 17, 18, 19],
        [21, 22],
        [23, 24, 25],
        [26, 27, 28, 29]
    ]

    print('----------------')
    lst1 = dynloop_loop(data)
    print(len(lst1))
    #print(lst1)

    print('----------------')
    lst2 = dynloop_rcsn(data)
    print(len(lst2))
    #print(lst2)

    print('----------------')
    lst3 = list(map(list, (itertools.product(*data))))
    print(len(lst3))
    #print(lst3)

    print('----------------')
    print(lst1 == lst2, lst2 == lst3)

 

/Users/abc/PycharmProjects/testpy/venv/bin/python /Users/abc/PycharmProjects/testpy/test.py

----------------

13824

----------------

13824

----------------

13824

----------------

True True

 

Process finished with exit code 0

Published 27 original articles · praised 4 · visits 9693

Guess you like

Origin blog.csdn.net/yoshubom/article/details/104124333