【问题标题】:Partial list Flattening in PythonPython中的部分列表展平
【发布时间】:2017-08-04 09:12:41
【问题描述】:

我有一个小问题,我缺乏相当多的 Python 经验。 假设一个列表:

list=[[40, 20, 45, 40], [[20, 10, 10, 30, 45, 20], [30, 20, 20, 30]]]

我想做一些我称之为“部分展平”的事情,因为预期的输出是:

[[40, 20, 45, 40], [20, 10, 10, 30, 45, 20], [30, 20, 20, 30]]

注意list 之前的长度为2,而预期输出的长度为3。问题是我事先不知道list 中的哪个元素嵌套更深一层。

This answer 和许多其他人并没有太大帮助,因为扁平化太远了。问题之后的输出是:

list=[40, 20, 45, 40, [20, 10, 10, 30, 45, 20], [30, 20, 20, 30]]

(请注意列表中前 4 个元素缺少括号。

【问题讨论】:

  • 那么,您想要所有最内层列表的列表吗?是否有像[1,2,[3,4]] 这样的输入列表,如果有,应该如何展平?
  • @tobias_k 这样的输入列表是不可能的。
  • 您告诉我们该特定示例的输出是什么,我理解这一点。但这个决定是基于什么?什么应该展平的规则是什么?完全不清楚逻辑应该是什么样的?一旦你到了那里,考虑到你已经看到并使用过其他扁平化方法,你自己解决了什么问题?
  • 请不要打电话给list 列表

标签: python list


【解决方案1】:

您可以创建一个递归函数,测试all 内部元素是否为列表。如果是,则递归应用该算法,否则生成列表本身。

def inner_lists(lst):
    if all(isinstance(x, list) for x in lst):
        for inner in lst:
            for x in inner_lists(inner):
                yield x
    else:
        yield lst

>>> lst = [[40, 20, 45, 40], [[20, 10, 10, 30, 45, 20], [30, 20, 20, 30]]]
>>> list(inner_lists(lst))
[[40, 20, 45, 40], [20, 10, 10, 30, 45, 20], [30, 20, 20, 30]]

或使用yield from(Python 3.3 及更高版本):

def inner_lists(lst):
    if all(isinstance(x, list) for x in lst):
        yield from (x for inner in lst for x in inner_lists(inner))
    else:
        yield lst

或者没有生成器:

def inner_lists(lst):
    if all(isinstance(x, list) for x in lst):
        return [x for inner in lst for x in inner_lists(inner)]
    else:
        return [lst]

【讨论】:

  • 在 Python 3 中你可以使用 yield from inner_lists(inner)
【解决方案2】:

如果您的列表只能包含数字或子列表(不能同时包含两者),您可以使用以下生成器函数:

In [25]: def partial_flattening(lst):
             for sub in lst:
                 if isinstance(sub[0], list):
                     yield from sub # in python 2.x use for i in sub: yeild i
                 else:          
                     yield sub
   ....:                 

In [26]: list(partial_flattening(lst))
Out[36]: [[40, 20, 45, 40], [20, 10, 10, 30, 45, 20], [30, 20, 20, 30]]

如果可能有两种类型的组合,那么根据您想要对数字做什么,您可以自定义功能。

或者作为更简洁的方法,您可以在列表理解中使用yield

In [29]: list([(yield from i) if isinstance(i[0], list) else (yield i) for i in lst])
Out[29]: [[40, 20, 45, 40], [20, 10, 10, 30, 45, 20], [30, 20, 20, 30]]

【讨论】:

  • 不知道您可以在列表组合中使用yield。但是,两者都只适用于单层嵌套(考虑到 OP 的示例,这可能完全没问题)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-14
  • 2019-08-11
  • 2022-11-28
  • 2021-09-07
  • 2012-04-25
相关资源
最近更新 更多