Я пытаюсь сделать более надежную нормализацию заполнения / размера для получения списка списков в формате пустого массива.
(я знаю, существует множество вопросов относительно этого "списка списков"в "массив", но я не видел ни одной попытки справиться с переменной глубиной списков. Поэтому я использую рекурсию, чтобы справиться с неизвестной глубиной вложенных списков.)
У меня естьфункция, которая получает нужную форму np.array.
Теперь при заполнении массива рекурсия с перечислением стала проблематичной - из-за отслеживания индексов на каждой глубине.
Проще говоря:
Мне нужна рекурсивная функция, которая делает это на неопределенной глубине:
# fill in the values of the ndarray `mat` with values from l
for row_ix, row in enumerate(l):
for col_ix, col in enumerate(row):
for val_ix, val in enumerate(col):
# ...
# ...
mat[row_ix, col_ix, val_ix] = l[row_ix][col_ix][val_ix]
Extra Detail
Вот мой MCVE (минимальный, полный и проверяемый пример) для желаемого результата / функциональности:
import numpy as np
# nested shapes of each list ( 2, [2, 4], [ [5,7], [3,7,4,9] ])
# desired shape (max of level) --> (2,4,9)
l = [[[1,2,5,6,7],
[0,2,5,34,5,6,7]],
[[5,6,7],
[0,2,5,7,34,5,7],
[0,5,6,7],
[1,2,3,4,5,6,7,8,9]]]
def nested_list_shape(lst):
# Provides the *maximum* length of each list at each depth of the nested list.
# (Designed to take uneven nested lists)
if not isinstance(lst[0], list):
return tuple([len(lst)])
return tuple([len(lst)]) + max([nested_list_shape(i) for i in lst])
shape = nested_list_shape(l) # (2,4,9)
mat = np.zeros(shape) # make numpy array of shape (2,4,9)
# fill in the values of the ndarray `mat` with values from l
for row_ix, row in enumerate(l):
for col_ix, col in enumerate(row):
for val_ix, val in enumerate(col):
mat[row_ix, col_ix, val_ix] = l[row_ix][col_ix][val_ix]
print(mat)
И вот что у меня естьпопытка до сих пор:
import numpy as np
# nested shapes of each list ( 2, [2, 4], [ [5,7], [3,7,4,9] ])
# desired shape (max of level) --> (2,4,9)
l = [[[1,2,5,6,7],
[0,2,5,34,5,6,7]],
[[5,6,7],
[0,2,5,7,34,5,7],
[0,5,6,7],
[1,2,3,4,5,6,7,8,9]]]
def nested_list_shape(lst):
# Provides the *maximum* length of each list at each depth of the nested list.
# (Designed to take uneven nested lists)
if not isinstance(lst[0], list):
return tuple([len(lst)])
return tuple([len(lst)]) + max([nested_list_shape(i) for i in lst])
# Useful for setting values in nested list
def get_element(lst, idxs):
# l[x][y][z][t] <==> get_element(l, [x,y,z,t])
#
# Given a list (e.g. `l = [[2,3],[5,6,7]]`),
# index the elements with an list of indices (one value for each depth)
# (e.g. if `idxs = [1,1]` then get_element returns the equivalent of l[1][1])
if len(idxs) == 1:
return lst[idxs[0]]
else:
return get_element(lst[idxs[0]], idxs[1:])
# ::Problem function::
def fill_mat(lst):
# Create numpy array for list to fill
shape = nested_list_shape(lst)
depth = len(shape)
x = np.zeros(shape)
# Use list of indices to keep track of location within the nested enumerations
ixs = [0] * depth
# ::PROBLEM::
# Recursive setting of ndarray values with nested list values
# d = depth of recursion
# l = list at that depth of recursion
# lst = full nested list
def r(l, ixs, d = 0):
for ix, item in enumerate(l):
# Change list of indices to match the position
ixs[d] = ix
# if the item is a value, we reach the max depth
# so here we set the values
if not isinstance(item, list):
x[tuple(ixs)] = get_element(lst, ixs)
else:
# increase the depth if we see a nested list (but then how to decrease ... :/)
d += 1
# return statement should likely go here, and somehow return x
r(item, ixs, d)
return x # ?? bad use of recursion
return r(lst, ixs)
shape = nested_list_shape(l) # (2,4,9)
mat = np.zeros(shape) # make numpy array of shape (2,4,9)
# fill in the values of the ndarray `mat` with values from l
print(fill_mat(l))
Функция get_element
делает l[row_ix][col_ix][val_ix]
эквивалентной функцией с ixs = [row_ix, col_ix, val_ix]
, но все еще существует проблема с отслеживанием каждого из них.
Кто-нибудь знаком с более простым методом рекурсивной обработки этих индексов?