Как применить функцию ко всем элементам списка (произвольной вложенности)
1,00
р.
р.
Отвечая на данный вопрос, я заинтересовался более универсальным решением... Есть список произвольной вложенности, например: ['1','2', ['1',['2','4',['5','6']]],'7','8'] Необходимо применить функцию ко всем элементам списка (включая все вложенные), сохранив при этом его структуру. Например преобразовать все элементы в числа и возвести их в квадрат, чтобы получилось: [1, 4, [1, [4, 16, [25, 36]]], 49, 64] Я опубликовал свой вариант решения, но мне было бы интересно увидеть альтернативные (более интересные) решения.
Ответ Чтобы поместу изменить, не создавая новые списки (поиск в глубину—depth-first search (DFS)): def apply_nested(func, lst, isatom=lambda item: not isinstance(item, list)): for i, item in enumerate(lst): if isatom(item): lst[i] = func(item) else: apply_nested(func, item, isatom) Здесь isatom() предикат определяет, что является неразрывным элементом (атомом) для заданного алгоритма: apply_nested(func, lst) вызывает func функцию для каждого атома в (глубоковложенном) списке lst. Похожее решение: flatten_gen(). Легко создать нерекурсивный вариант (поиск в ширину—breadth-first search (BFS), если использовать deque.popleft()): def apply_nested(func, lst, isatom=lambda item: not isinstance(item, list)): stack = [lst] while stack: lst = stack.pop() for i, item in enumerate(lst): if isatom(item): lst[i] = func(item) else: stack.append(item) Пример: >>> nested = ['1','2', ['1',['2','4',['5','6']]],'7','8'] >>> apply_nested(lambda atom: int(atom)**2, nested) >>> nested [1, 4, [1, [4, 16, [25, 36]]], 49, 64] Аналогично, можно определить функции, которые возвращают новые значения, не изменяя ввода (DFS): def map_nested(func, lst, isatom=lambda item: not isinstance(item, list)): return [func(item) if isatom(item) else map_nested(func, item, isatom) for item in lst] Нерекурсивный вариант: def map_nested(func, lst, isatom=lambda item: not isinstance(item, list)): result = [] stack = [(lst, result)] while stack: lst, new_lst = stack.pop() for item in lst: if isatom(item): new_lst.append(func(item)) else: # item is a sublist (collection) sublist = [] new_lst.append(sublist) stack.append((item, sublist)) return result Пример: >>> map_nested(lambda atom: int(atom)**2, nested)) [1, 4, [1, [4, 16, [25, 36]]], 49, 64]