交错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。我可以改用它吗? @user2829177izip_longest
与zip
略有不同,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个长度排列[重复]