简体   繁体   English

通过放置一个列表中的每个第n个项目和另一个列表中的其他项目来合并Python中的列表?

[英]Merge lists in Python by placing every nth item from one list and others from another?

I have two lists, list1 and list2 . 我有两个列表, list1list2

Here len(list2) << len(list1) . 这里len(list2) << len(list1)

Now I want to merge both of the lists such that every nth element of final list is from list2 and the others from list1 . 现在我想合并两个列表,使得最终列表的每个第n个元素 来自list2而其他 元素 来自list1

For example: 例如:

list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

list2 = ['x', 'y']

n = 3

Now the final list should be: 现在最后的清单应该是:

['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']

What is the most Pythonic way to achieve this? 实现这一目标的最恐怖的方法是什么?

I want to add all elements of list2 to the final list, final list should include all elements from list1 and list2 . 我想将list2所有元素添加到最终列表中,最终列表应包括list1list2所有元素。

Making the larger list an iterator makes it easy to take multiple elements for each element of the smaller list: 使较大的列表成为迭代器可以轻松地为较小列表的每个元素获取多个元素:

list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
list2 = ['x', 'y'] 
n = 3

iter1 = iter(list1)
res = []
for x in list2:
    res.extend([next(iter1) for _ in range(n - 1)])
    res.append(x)
res.extend(iter1)

>>> res
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']

This avoids insert which can be expensive for large lists because each time the whole list needs to be re-created. 这避免了insert ,这对于大型列表来说可能是昂贵的,因为每次需要重新创建整个列表。

To preserve the original list, you could try the following: 要保留原始列表,可以尝试以下操作:

result = copy.deepcopy(list1)
index = n - 1
for elem in list2:
    result.insert(index, elem)
    index += n

result 结果

['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']

Using the itertools module and the supplementary more_itertools package , you can construct an iterable solution a couple different ways. 使用itertools模块和补充的more_itertools ,您可以通过几种不同的方式构建可迭代的解决方案。 First the imports: 首先进口:

import itertools as it, more_itertools as mt

This first one seems the cleanest, but it relies on more_itertools.chunked() . 第一个似乎是最干净的,但它依赖于more_itertools.chunked()

it.chain(*mt.roundrobin(mt.chunked(list1, n-1), list2))

This one uses only more_itertools.roundrobin() , whose implementation is taken from the itertools documentation, so if you don't have access to more_itertools you can just copy it yourself. 这个只使用more_itertools.roundrobin() ,其实现来自itertools文档,因此如果您无权访问more_itertools您可以自己复制它。

mt.roundrobin(*([iter(list1)]*(n-1) + [list2]))

Alternatively, this does nearly the same thing as the first sample without using any more_itertools -specific functions. 或者,这与第一个样本more_itertools而不使用任何more_itertools特定的函数。 Basically, grouper can replace chunked , but it will add None s at the end in some cases, so I wrap it in it.takewhile to remove those. 基本上, grouper可以替代chunked ,但在某些情况下它会在最后添加None ,所以我将它包裹在其中。 it.takewhile去除它们。 Naturally, if you are using this on lists which actually do contain None , it will stop once it reaches those elements, so be careful. 当然,如果你在实际上包含None列表上使用它,它会在到达那些元素时停止,所以要小心。

it.takewhile(lambda o: o is not None,
   it.chain(*mt.roundrobin(mt.grouper(n-1, list1), list2))
)

I tested these on Python 3.4, but I believe these code samples should also work in Python 2.7. 我在Python 3.4上测试了这些,但我相信这些代码示例也适用于Python 2.7。

What about the below solution? 以下解决方案怎么样? However I don't have a better one... 但是我没有更好的...

>>> list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
>>> list2 = ['x', 'y']
>>> n = 2
>>> for i in range(len(list2)):
...     list1.insert(n, list2[i])
...     n += 3
...     
... 
>>> list1
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']

n is 2 because the index of third element in a list is 2, since it starts at 0. n是2,因为列表中第三个元素的索引是2,因为它从0开始。

list(list1[i-1-min((i-1)//n, len(list2))] if i % n or (i-1)//n >= len(list2) else list2[(i-1)//n] for i in range(1, len(list1)+len(list2)+1))

Definitely not pythonic, but I thought it might be fun to do it in a one-liner. 绝对不是pythonic,但我认为在单行中进行它可能很有趣。 More readable (really?) version: 更可读(真的吗?)版本:

list(
    list1[i-1-min((i-1)//n, len(list2))]
        if i % n or (i-1)//n >= len(list2)
        else
    list2[(i-1)//n]
        for i in range(1, len(list1)+len(list2)+1)
)

Basically, some tinkering around with indexes and determining which list and which index to take next element from. 基本上,一些修改索引并确定哪个列表和哪个索引从下一个元素。

Yet another way, calculating the slice steps: 另一种方法是,计算切片步骤:

list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
list2 = ['x', 'y'] 
n = 3

res = []
m = n - 1
start, end = 0, m
for x in list2:
    res.extend(list1[start:end])
    res.append(x)
    start, end = end, end + m
res.extend(list1[start:])

>>> res
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']
list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
list2 = ['x', 'y']
n = 3
new = list1[:]

for index, item in enumerate(list2):
    new[n * (index + 1) - 1: n * (index + 1) - 1] = item

print(new)

I admire @David Z's use of more_itertools . 我很佩服@David Z使用more_itertools Updates to the tools can simplify the solution: 对工具的更新可以简化解决方案:

import more_itertools as mit

n = 3
groups = mit.windowed(list1, n-1, step=n-1)
list(mit.flatten(mit.interleave_longest(groups, list2)))
# ['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']

Summary: list2 is being interleaved into groups from list1 and finally flattened into one list. 摘要: list2正在从list1交错到组中,最后扁平化为一个列表。

Notes 笔记

  1. groups : n-1 size sliding windows, eg [('a', 'b'), ('c', 'd'), ('e', 'f'), ('g', 'h')] groupsn-1大小的滑动窗口,例如[('a', 'b'), ('c', 'd'), ('e', 'f'), ('g', 'h')]
  2. interleave_longest is presently equivalent to roundrobin interleave_longest目前相当于roundrobin
  3. None is the default fillvalue. None是默认填充值。 Optionally remove with filter(None, ...) 可选择使用filter(None, ...)删除filter(None, ...)

Maybe here is another solution, slice the list1 the correct index then add the element of list2 into list1 . 也许这是另一种解决方案,将list1切成正确的索引,然后将list2的元素添加到list1

>>> list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
>>> list2 = ['x', 'y'] 
>>> n = 3
>>> for i in range(len(list2)):
...     list1 = list1[:n*(i+1) - 1] + list(list2[i]) + list1[n*(i+1)-1:]
... 
>>> list1
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM