【问题标题】:interleaving 2 lists of unequal lengths [duplicate]交错2个长度不等的列表[重复]
【发布时间】: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 是的
  • 这是一个测验问题吗?

标签: python list for-loop indexing


【解决方案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']

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

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
猜你喜欢
  • 2018-11-21
  • 1970-01-01
  • 2012-12-23
  • 1970-01-01
  • 1970-01-01
  • 2014-10-02
  • 2017-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多