交错2个长度不等的列表[重复]

Posted

技术标签:

【中文标题】交错2个长度不等的列表[重复]【英文标题】:interleaving 2 lists of unequal lengths [duplicate] 【发布时间】:2013-11-21 22:12:00 【问题描述】:

我希望能够交错两个长度可能不相等的列表。我所拥有的是:

  def interleave(xs,ys):
    a=xs
    b=ys
    c=a+b
    c[::2]=a
    c[1::2]=b
    return c

这适用于长度相等或仅 +/-1 的列表。但是,如果假设 xs=[1,2,3] 和 ys= ["hi,"bye","no","yes","why"] 会出现以下消息:

c[::2]=a
ValueError: attempt to assign sequence of size 3 to extended slice of size 4

如何使用索引解决此问题?还是我必须使用 for 循环? 编辑:我想要的是让额外的值出现在最后。

【问题讨论】:

你想要发生什么?输出应该是什么? @DavidRobinson 我想做的是让额外的值出现在末尾。 那么[1, "hi, 2, "bye", 3, "no","yes","why"]? @DavidRobinson 是的 这是一个测验问题吗? 【参考方案1】:

您可以在这里使用itertools.izip_longest

>>> from itertools import izip_longest
>>> xs = [1,2,3]
>>> ys = ["hi","bye","no","yes","why"]
>>> s = object()
>>> [y for x in izip_longest(xs, ys, fillvalue=s) for y in x if y is not s]
[1, 'hi', 2, 'bye', 3, 'no', 'yes', 'why']

使用来自itertools 的roundrobin 配方,此处不需要标记值:

from itertools import *
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))

演示:

>>> list(roundrobin(xs, ys))
[1, 'hi', 2, 'bye', 3, 'no', 'yes', 'why']
>>> list(roundrobin(ys, xs))
['hi', 1, 'bye', 2, 'no', 3, 'yes', 'why']

【讨论】:

我有一个 zip 函数,它可以压缩 xs 和 ys。我可以改用它吗? @user2829177 izip_longestzip 略有不同,zip 将输出截断为最短列表。 有更简单的方法吗? @user2829177 您可能会发现来自 itertools 的循环方法有点帮助。我已经在我的回答中发布了。 @user2829177 查看 DSM 的第一个解决方案,IMO 这是最简单的方法。【参考方案2】:

你可以使用heapq.merge:

xs = [1, 2, 3]
ys = ['hi', 'bye', 'no', 'yes', 'why']

import heapq
interleaved = [v for i, v in heapq.merge(*[enumerate(el) for el in (xs, ys)])]
# [1, 'hi', 2, 'bye', 3, 'no', 'yes', 'why']

这避免了对标记值和扁平化的需要。

请改用roundrobin recipe 来更有效地实现这一目标,而无需让项目具有可比性。

【讨论】:

我已经钻了进去,不要修改使用 for 循环迭代的序列的内容。这是一种情况,不要这样做除非你知道你在做什么?我正在尝试弄清楚为什么在这个生成器中它是可以的,有什么提示吗? @wwii 这不是一个好主意。 (在疲倦的帖子中归咎于晚上 11 点)。它适用于 2 个序列。但是,对于在较短的之前的连续相等长度的长度 - 下一个项目的顺序变得“不稳定” - 使用 roundroubin 配方是执行此操作的正确方法......我已经删除了代码并更新了答案效果。【参考方案3】:

好的,这是我的条目:

>>> from itertools import chain
>>> xs = [1,2,3]
>>> ys = ["hi","bye","no","yes","why"]
>>> xi, yi = iter(xs), iter(ys)
>>> list(chain.from_iterable(zip(xi, yi))) + list(xi) + list(yi)
[1, 'hi', 2, 'bye', 3, 'no', 'yes', 'why']

或者,

>>> [i for row in zip(xi, yi) for i in row] + list(xi) + list(yi)

也会起作用(这只是用于扁平化的 listcomp 成语,正如@hcwhsa 所使用的那样)。我的第一个想法是

>>> list(zip(*sorted(list(enumerate(xs)) + list(enumerate(ys)))))[1]
(1, 'hi', 2, 'bye', 3, 'no', 'yes', 'why')

但这只是@Jon Clements 效率低得多的版本(我使用了低效的排序,他使用了高效的堆队列。)

[我一直在尝试尝试使用 cycle 工作,但这似乎并不像我希望的那么容易:事实证明,我只是在努力重新实现轮询方案@hcwsha 已发布,所以没有必要完成它。 :^)]

【讨论】:

我们实际上是在 Python 会议室里讨论这个问题 - 在 Python 3.x 上,我们的方法会因为需要进行比较而中断...... :) @Jon Clements:嘿,我的官方条目会起作用,那里没有比较。 :^) 是的...我注意到我还重写了一个非 itertools 版本的循环 :)【参考方案4】:

保持简单:

def interleave(xs,ys):
    stop = min(len(xs), len(ys))
    suffix = max(xs, ys, key = len)[stop:]
    out = list()
    for pair in zip(xs, ys):
        out.extend(pair)
    out.extend(suffix)
    return out

注意事项: Python 2.7 假设列表作为参数传递。

【讨论】:

我认为您的 out += xs[index] + ys[index] 行需要是 out += [xs[index], ys[index]],或者使用 1 元素切片或其他东西来确保您连接列表。 Python 3 中没有 xrange。但这些很容易修复。 @DSM,我在单个测试用例上进行了尝试,它可以工作,interleave(list('ab'), list('cdefghijklmnop'))。我应该说我的答案是 Python 2 吗?这里是否有一个假设,除非另有说明,否则答案是 3? 您的测试用例有点特别,因为它们是单字符的字符串。试试[1,2,3]['hi', 'bye', 'no', 'yes', 'why'],甚至['ab','cd'],['ef','gh']。至于 Python 3 的问题,我很抱歉——我确定问题有 python 3 标签,但似乎没有。 感谢您的推动。固定的。在修复它时,让我想起了我已经看过的东西。 如果我不允许使用除 len、range、list、str、print 和 .append 以外的任何函数怎么办?我有一个找到最小值的功能,所以我调整了它。但我不明白如何更换 .extend @wwii

以上是关于交错2个长度不等的列表[重复]的主要内容,如果未能解决你的问题,请参考以下文章

从n个整数列表(可能长度不等)中进行所有可能的n个长度排列[重复]

Zip_longest Plus:遍历不同长度的列表[重复]

两个长度不等的列表之间的排列

一日一技:不等长度列表的同时迭代

Python,如何将长度不等的嵌套列表写入csv文件?

如何计算两个列表的所有交错?