RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 608684
Accepted
MaxU - stop genocide of UA
MaxU - stop genocide of UA
Asked:2020-12-28 06:43:56 +0000 UTC2020-12-28 06:43:56 +0000 UTC 2020-12-28 06:43:56 +0000 UTC

如何将函数应用于列表的所有元素(任意嵌套)

  • 772

回答这个问题,我开始对更通用的解决方案感兴趣......

有一个任意嵌套的列表,例如:

['1','2', ['1',['2','4',['5','6']]],'7','8']

有必要将该函数应用于列表的所有元素(包括所有嵌套元素),同时保持其结构。

例如,将所有元素转化为数字,然后平方得到:

[1, 4, [1, [4, 16, [25, 36]]], 49, 64]

我发布了自己的解决方案,但我有兴趣查看替代(更有趣)的解决方案。

python
  • 4 4 个回答
  • 10 Views

4 个回答

  • Voted
  1. MaxU - stop genocide of UA
    2020-12-28T06:44:16Z2020-12-28T06:44:16Z

    解决方案:

    def map_nested(lst, func=lambda x: x):
        assert isinstance(lst, list), '"lst" parameter is NOT a list'
        return [map_nested(lst[i], func)
                if isinstance(lst[i], list)
                else func(lst[i])
                for i in range(len(lst))]
    

    测试:

    In [154]: lst = ['1', '2', ['1', ['2', '4', ['5', '6']]], '7', '8']
    
    In [155]: map_nested(lst, lambda x: int(x)**2)
    Out[155]: [1, 4, [1, [4, 16, [25, 36]]], 49, 64]
    
    • 9
  2. m9_psy
    2020-12-28T07:52:29Z2020-12-28T07:52:29Z

    很难发明一些东西——一切似乎都在你的决定中。但是,您可以尝试在一行中进行一些(不必要的?)更改 + 一个函数。如果需要,也可以将大型函数放在 1 行中,但这已经太多了:

    import timeit
    
    
    def map_nested(lst, func=lambda x: x, forbidden_types=(str, int)):
        container_type = type(lst)
        if hasattr(lst, '__iter__') and type(lst) not in forbidden_types:
            return container_type(map_nested(item, func) for item in lst)
        else:
            try:
                return func(lst)
            except:
                return lst
    
    
    def map_nested_1line(lst, func=lambda x: x):
        return [map_nested_1line(item, func) for item in lst] if type(lst) is list else func(lst)
    

    更新: 早上比晚上更明智,经过深思熟虑,我想到了这个函数的非递归版本。非递归是好的,因为它不会在具有递归长度限制的操作系统上的长而重度嵌套列表上崩溃。坏消息是它非常慢。非递归解决方案的本质是将嵌套列表的进入和退出顺序输入到一个特殊的数组中。我们找到一个嵌套数组 - 我们输入一个指向它的指针 + 特殊的索引。贮存。我们离开它 - 我们提取指针和索引。

    # Also non-recursive. Yay!
    def map_nested_inplace(lst, func=lambda x: x, forbidden_types=(str, int)):
        # forbidden_types не используется
        processed_elements = 0
        # assert type(lst) is list # blah-blah
        current_container = lst
        containers_repo = [[current_container, 0]]
        # До тех пор, пока не были обработаны все списки и под-списки
        while len(containers_repo) != 0:
            while True:
                try:
                    # Следующий элемент в текущем списке. 
                    # Может быть как числом, так и новым под-списком
                    next_one = current_container[containers_repo[-1][1]]
                    break
                # Исключение означает, что под-список кончился. 
                # Т.к. он кончился, то убираем его из хранилища 
                # и пробуем извлечь следующий элемент
                except IndexError:
                    containers_repo.pop()
                    if len(containers_repo) == 0:
                        break
                    current_container = containers_repo[-1][0]
            if len(containers_repo) != 0:
                if type(next_one) is list:
                    # Это под-список, а не число. 
                    # Заносим под-список в хранилище и 
                    # на следующей итерации открываем уже его
                    containers_repo[-1][1] += 1
                    current_container = next_one
                    containers_repo.append([current_container, 0])
                else:
                    current_container[containers_repo[-1][1]] = func(current_container[containers_repo[-1][1]])
                    containers_repo[-1][1] += 1
                    # ради небольшой проверки
                    processed_elements += 1
    
    
    # set также работает, но непохоже, чтобы он сохранял порядок
    lst = ['1', 'an error', ('1', ['2', '4', (5, '6')]), '7', 8]
    lst_simple = ['1', '2', ['1', ['2', '4', ['5', '6']]], '7', '8']
    lst_another_simple = ['1', '2', ['1', ['2', '4', ['5', '6']], ['6', '6', '6'], ['8', '8']], '7', ['11'], '8']
    print(map_nested(lst, lambda x: int(x)**2))
    print(map_nested_1line(lst_simple, lambda x: int(x)**2))
    print(map_nested_1line([], lambda x: int(x)**2))
    map_nested_inplace(lst_another_simple, lambda x: int(x)**2)
    print(lst_another_simple)
    

    还有一些测试:

    import random
    test_array = []
    container_tree = [test_array]
    current_container = container_tree[-1]
    TOTAL_AMOUNT = 10000
    NEW_LEVEL_PROBABILITY = 0.5
    for i in range(TOTAL_AMOUNT):
        if random.random() >= NEW_LEVEL_PROBABILITY:
            current_container.append([])
            container_tree.append(current_container[-1])
            current_container = current_container[-1]
        elif len(container_tree) > 1:
            current_container = container_tree[-2]
        current_container.append(str(random.randint(0, 20)))
    
    # Для работоспособности рекурсивных методов
    # Впрочем, без старта новго потока с threading.stack_size(<Big value>) все равно не будет работать :(
    import sys
    if sys.getrecursionlimit() < len(container_tree) * 2:
        sys.setrecursionlimit(len(container_tree) * 2)
    
    setup_statement = """from __main__ import test_array, """
    
    # Не используется lambda x**2, потому что 
    # в inplace квадраты будут накатываться до тех пор, 
    # пока хватит памяти - список для каждого прохода должен генерироваться заново
    
    print(timeit.timeit("map_nested_inplace(test_array)", setup=setup_statement + "map_nested_inplace", number=100))
    print(timeit.timeit("map_nested_1line(test_array)", setup=setup_statement + "map_nested_1line", number=100))
    print(timeit.timeit("map_nested(test_array)", setup=setup_statement + "map_nested", number=100))
    
    >>> 1.8096923486838081  # Без рекурсии
    >>> 0.9477624593712808  # Однострочник
    >>> 1.827232542223693  # Большая функция
    
    • 9
  3. Best Answer
    jfs
    2020-12-29T02:34:22Z2020-12-29T02:34:22Z

    要在不创建新列表的情况下就地修改(深度优先搜索 (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():

    创建非递归变体很容易(如果使用广度优先搜索 (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]
    
    • 9
  4. Frank
    2020-03-10T23:14:16Z2020-03-10T23:14:16Z

    立刻想到了这个决定。

    def anon(l, func=lambda x: int(x) ** 2):
        for n, i in enumerate(l):
            if type(i) != list:
                l[n] = func(i)
            else:
                anon(i)
        return l
    
    lst = ['1', '2', ['1', ['2', '4', ['5', '6']]], '7', '8']
    print(anon(lst))
    
    >>> [1, 4, [1, [4, 16, [25, 36]]], 49, 64]
    
    • 2

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何停止编写糟糕的代码?

    • 3 个回答
  • Marko Smith

    onCreateView 方法重构

    • 1 个回答
  • Marko Smith

    通用还是非通用

    • 2 个回答
  • Marko Smith

    如何访问 jQuery 中的列

    • 1 个回答
  • Marko Smith

    *.tga 文件的组重命名(3620 个)

    • 1 个回答
  • Marko Smith

    内存分配列表C#

    • 1 个回答
  • Marko Smith

    常规赛适度贪婪

    • 1 个回答
  • Marko Smith

    如何制作自己的自动完成/自动更正?

    • 1 个回答
  • Marko Smith

    选择斐波那契数列

    • 2 个回答
  • Marko Smith

    所有 API 版本中的通用权限代码

    • 2 个回答
  • Martin Hope
    jfs *(星号)和 ** 双星号在 Python 中是什么意思? 2020-11-23 05:07:40 +0000 UTC
  • Martin Hope
    hwak 哪个孩子调用了父母的静态方法?还是不可能完成的任务? 2020-11-18 16:30:55 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    Arch ArrayList 与 LinkedList 的区别? 2020-09-20 02:42:49 +0000 UTC
  • Martin Hope
    iluxa1810 哪个更正确使用:if () 或 try-catch? 2020-08-23 18:56:13 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5