【问题标题】:Iterate through a nested list and pick certain elements and create a new list遍历嵌套列表并选择某些元素并创建一个新列表
【发布时间】:2021-12-15 09:50:24
【问题描述】:

一个例子:

list = [[2, 1, 2, 3, 4],
       [0, 4, 5],
       [1, 8, 9]]

所以嵌套列表中的第一个索引决定了后面哪些数字将被放入非嵌套列表中。

[2, 1, 2, 3, 4] -> 2: so 1 and 2 gets picked up
[0, 4, 5] -> 0: no number gets picked up
[1, 8, 9] -> 1; number 8 gets picked up

输出将是:

[1, 2, 8]

这是我目前所拥有的:

def nested_list(numbers):
    if isinstance(numbers[0], list):
        if numbers[0][0] > 0:
            nested_list(numbers[0][1:numbers[0][0] + 1])
    else:
        numbers = list(numbers[0])

    return numbers + nested_list(numbers[1:])

我尝试通过递归获取列表,但出现了问题。我错过了什么或者即使没有递归也可以做到这一点?

【问题讨论】:

    标签: python list recursion nested nested-lists


    【解决方案1】:

    您尝试在此处使用列表推导和元组解包。

    [val for idx, *rem in lst for val in rem[:idx]] 
    # [1, 2, 8]
    

    NB 此解决方案假定您始终拥有大小为 1 或更大的子列表。我们可以使用filter(None, lst)过滤掉空的子列表

    【讨论】:

    • 开箱不错。
    【解决方案2】:
    list1=[[2, 1, 2, 3, 4],
           [0, 4, 5],
           [1, 8, 9]]
    list2= []
    
    for nested_list in list1:
        for i in range(nested_list[0]):
            list2.append(nested_list[i+1])
    

    【讨论】:

      【解决方案3】:

      你可以试试List-comprehension:

      >>> [sub[i] for sub in lst for i in range(1, sub[0]+1) ]
      [1, 2, 8]
      

      PS:该解决方案期望每个子列表都是一个非空列表,否则它会由于sub[0]而抛出IndexError异常。

      【讨论】:

      • 我们可以避免使用IndexError,也许可以使用filter(None, lst)。不错。
      • @Ch3steR 为什么要默默地避开IndexError?如果出现问题,应警告调用者。
      • @Stef filter 不会抑制IndexError,我的意思是说如果OP 的示例输入是[ [], [] ],那么输出会是什么?引发错误?返回空列表?如果 OP 想要引发错误,请不要使用 filter,如果预期输出为空,请使用 filter。同样,我评论的大部分内容只是假设,OP 需要澄清。
      【解决方案4】:

      另一个列表理解

      sum([x[1:x[0] + 1] for x in arr], [])
      # [1, 2, 8]
      

      【讨论】:

        【解决方案5】:

        使用builtin function map 应用拾取功能,并使用itertools.chain 展平结果列表:

        def pick(l):
            return l[1:1+l[0]]
        
        ll = [[2, 1, 2, 3, 4], [0, 4, 5], [1, 8, 9]]
        
        print( list(map(pick, ll)) )
        # [[1, 2], [], [8]]
        
        print( list(itertools.chain.from_iterable((map(pick, ll)))) )
        # [1, 2, 8]
        

        或者,使用list comprehension

        ll = [[2, 1, 2, 3, 4], [0, 4, 5], [1, 8, 9]]
        
        print( [x for l in ll for x in l[1:1+l[0]]] )
        # [1, 2, 8]
        

        两个重要说明:

        • 我已将您的列表重命名为 ll 而不是 list。这是因为list已经是python中内置类list的名称。隐藏内置函数的名称是非常危险的,并且可能会产生意想不到的后果。我强烈建议您在命名自己的变量时不要使用内置函数的名称。

        • 对于上述两种解决方案,错误处理的行为相同:如果其中一个子列表为空,则会引发异常IndexError(因为我们需要访问第一个元素才能知道要选择多少元素,所以会出现错误如果没有第一个元素,则引发)。但是,如果其中一个子列表中没有足够的元素,则不会引发异常。例如,如果其中一个子列表是[12, 3, 4],那么上面的两个解决方案都会默默地选择两个元素 3 和 4,即使他们被要求选择 12 个元素而不仅仅是 2。如果你想为这种情况,可以在第一个解决方案中修改函数pick

        def pick(l):
            if len(l) == 0 or len(l) <= l[0]:
                raise ValueError('in function pick: two few elements in sublist {}'.format(l))
            return l[1:1+l[0]]
        
        ll = [[2, 1, 2, 3, 4], [0, 4, 5], [1, 8, 9], [12, 3, 4]]
        
        print( [x for l in ll for x in l[1:1+l[0]]] )
        # [1, 2, 8, 3, 4]
        
        print( [x for l in ll for x in pick(l)] )
        # ValueError: in function pick: two few elements in sublist [12, 3, 4]
        

        【讨论】:

          猜你喜欢
          • 2014-04-12
          • 1970-01-01
          • 2016-11-22
          • 2019-03-27
          • 1970-01-01
          • 2021-10-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多