Python:将子列表中的每个第一,第二,第三元素

时间:2018-09-05 23:35:16

标签: python

我正在使用Python 2.7并具有以下功能:

pipe

我想创建一个一维列表,其中元素按子列表中的位置顺序排列,然后按子列表的顺序排列。因此,上述列表的正确输出是:

my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

这是我的(不正确的)尝试:

[1, 4, 7, 2, 5, 8, 3, 6, 9]

这使我的2维列表变平,并且给了我:

def reorder_and_flatten(my_list):
    my_list = [item for sublist in my_list for item in sublist]
    result_nums = []
    for i in range(len(my_list)):
        result_nums.extend(my_list[i::3])
    return result_nums
result = reorder_and_flatten(my_list)

此列表的前半部分正确,但后半部分不正确。

我也希望我的函数只能处理2个子列表。例如,如果给出:

[1, 4, 7, 2, 5, 8, 3, 6, 9, 4, 7, 5, 8, 6, 9, 7, 8, 9]

正确的输出是:

[[1, 2, 3], [], [7, 8, 9]

有什么想法吗?

谢谢!

4 个答案:

答案 0 :(得分:2)

您要先进行拼合然后重新排序,这比重新排序然后进行拼合要困难得多。

首先,对于您的第一个问题,就是“解压缩”,如zip的文档中所述:

>>> my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> list(zip(*my_list))
... [(1, 4, 7), (2, 5, 8), (3, 6, 9)]

(在Python 2.7中,您可以在此处编写zip(…)而不是list(zip(…)),但是这样,同一示例在2.x和3.x中的工作原理相同。)

然后,您已经知道如何扁平化:

>>> [item for sublist in zip(*my_list) for item in sublist]
[1, 4, 7, 2, 5, 8, 3, 6, 9]

但是对于第二种情况,情况变得有些复杂,其中某些列表可能为空(或可能更短?)。

没有类似于zip的函数,但是会跳过缺少的值。您可以轻松编写一个。但是相反,有一个 函数,它类似于zip,但用None(或您喜欢的其他任何东西)izip_longest填充缺失值。因此,我们可以使用它,然后在展平时过滤掉None值:

>>> my_list = [[1, 2, 3], [], [7, 8, 9]]
>>> from itertools import izip_longest
>>> list(izip_longest(*my_list))
[(1, None, 7), (2, None, 8), (3, None, 9)]
>>> [item for sublist in izip_longest(*my_list) for item in sublist if item is not None]
[1, 7, 2, 8, 3, 9]

(在Python 3中,函数izip_longest重命名为zip_longest。)


值得注意的是,ShadowRanger's answer涵盖的roundrobin食谱是解决此问题的更好方法,甚至更易于使用(只需从文档中复制并粘贴,或{ {1}},然后从那里使用它)。 很难理解-但是值得花些时间来理解它(并在遇到问题时寻求帮助)。

答案 1 :(得分:1)

        <div *ngFor="let item of myFormArray.controls; let i=index">
            <div formGroupName="{{i}}">
                <input formControlName="myFormGroupSubControl1" />
                <input formControlName="myFormGroupSubControl2" />

result = [l[i] for i in range(max(len(v) for v in my_list)) for l in my_list if l]

答案 2 :(得分:1)

The itertools module's recipes section提供了insert into [Fleet].[dbo].[AccountsReports] ([AccountId], [ReportId], [ReportName]) SELECT @account AccountId ,[ReportId] ,[Name] FROM [Fleet].[dbo].[Reports] t1 where ReportId in (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,54) and not exists ( SELECT 1 FROM [Fleet].[dbo].[Reports] t2 WHERE t1.ReportId = t2.ReportId and t1.Name = t2.Name ) 的食谱,可以完全满足您的需求。它会产生一个生成器,但是您的预期行为将显示为:

roundrobin

您的原始代码的主要问题是它遍历# define roundrobin recipe here from itertools import cycle, islice def roundrobin(*iterables): "roundrobin('ABC', 'D', 'EF') --> A D E B F C" # Recipe credited to George Sakkis pending = len(iterables) nexts = cycle(iter(it).next for it in iterables) while pending: try: for next in nexts: yield next() except StopIteration: pending -= 1 nexts = cycle(islice(nexts, pending)) def reorder_and_flatten(my_list): return list(roundrobin(*my_list)) ,并以for i in range(len(my_list)):扩展。问题是,这最终会从索引3开始复制元素(索引3已被选择为索引0切片的第二个元素)。这里还有很多其他小的逻辑错误,因此重用配方要容易得多。

这将是相当有效的,并且比大多数手动解决方案具有更好的通用性(即使子列表的长度不均匀,它也可以正确轮转,并且不需要二次通过过滤或任何形式的特殊处理即可my_list[i::3]就像None一样)。

答案 3 :(得分:1)

如果您愿意使用第三方库,则可以使用NumPy和np.ndarray.ravel

import numpy as np

A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

res_a = A.ravel('F')  # array([1, 4, 7, 2, 5, 8, 3, 6, 9])

对于有一个或多个空列表的情况,可以使用filter删除空列表:

B = np.array(list(filter(None, [[1, 2, 3], [], [7, 8, 9]])))

res_b = B.ravel('F')  # array([1, 7, 2, 8, 3, 9])

两个解决方案都要求非空子列表包含相同数量的项目。如果必须进行列表转换,则可以使用res_a.tolist()

尽管这些“黑匣子”方法不会给您带来太多帮助,但对于大型数组,它们比基于list的操作要快。另请参见What are the advantages of NumPy over regular Python lists?