我不知道如何给出一个准确的标题,但这就是问题所在。
问题:
我想给出一个已经保留了一些位置的排名列表(想象一些顶级列表)。
假设我有7个位置[1, 2, 3, 4, 5, 6, 7, 8]
,其中一些已经保留了位置1,3,4,7,9。(因为我们只有8个槽位,所以保留的位置9将意味着最后一个槽位。)
那么我还剩下2 5 6个槽,我必须用其他对象填充它们
简化问题:
我有两个列表:
>>> a = [1, 3, 4, 7, 9]
>>> b = [object_x, object_y, object_z]
我想把它们合并成这个
>>> c = [1, object_x, 3, 4, object_y, object_z, 7, 9]
(这里可以取'object_x'为0)
就是这样,只是想看看是否有一个优雅的方法来实现这个
(根据评论编辑整个问题。非常感谢大家。
您可以使用生成器:
def merge(a, b):
b_clone = b[:]
for n in range(min(a), max(a) + 1):
if n in a:
yield n
elif b_clone:
yield b_clone.pop(0)
我相信这涵盖了边缘情况,然而,我同意其他人的观点,似乎一定有更好的方法来做到这一点。也许有必要解释一下你正在尝试做的事情的背景。也许有一种不需要这些的方法。
def merge(a, b):
b = list(b)
a = iter(a)
current = 1
for item in a:
while item != current:
if b:
yield b.pop(0)
else:
yield item
yield from a # <3.3 use `for item in a: yield item` instead.
return
current += 1
yield item
current += 1
这似乎按照你的规格工作:
>>> print(list(merge([1, 3, 4, 7, 9], [0, 0, 0])))
[1, 0, 3, 4, 0, 0, 7, 9]
>>> print(list(merge([2, 4, 5], [1, 3])))
[1, 2, 3, 4, 5]
也不清楚在b
中给定额外的元素会发生什么-这忽略了它们,但是在末尾添加yield from b
(或,<3.3 for item in b: yield item
)会将它们作为最后的元素。
这应该也可以:
>>>a = [2, 3, 5, 6, 7, 9]
>>>b = [0, 0, 0]
>>>length = len(a)
>>>i = 0
>>>while (i < length):
if a[i] != i+1:
a.insert(i, b.pop(0))
length += 1
i += 1
>>>print(a)
[0, 2, 3, 0, 5, 6, 7, 0, 9]
谢谢大家,我的灵感来自于@jurgenreza
>>> a = [1, 3, 4, 7, 9]
>>> b = [0, 0, 0]
>>> for i in a:
b.insert(i - 1, i)
>>> print b
[1, 0, 3, 4, 0, 0, 7, 9]
一开始就避免进行这种合并可能会更好。如果你事先知道有多少个可能的排名,你可以从包含None
的列表开始,并且每次占用一个空间时,使用列表项分配而不是附加来设置它。那么最终的合并就像这样简单:
def merge(a, b):
b = iter(b)
for i,x in a:
if x is None:
a[i] = next(b)
如果你愿意,你可以把这整个数据结构放到一个类中,这也允许你,例如,检查当你试图覆盖一个被占用的位置(如果这将是一个错误):
class Ranks:
def __init__(self, size):
self._list = [None] * size
def __getitem__(self, position):
return self._list[position]
def __setitem__(self, position, val):
if self._list[position] is None:
raise ValueError('attempting to clobber existing rank data')
self._list[position] = val