在每个第 n 个元素之后插入 Python 列表中的元素

Posted

技术标签:

【中文标题】在每个第 n 个元素之后插入 Python 列表中的元素【英文标题】:Insert element in Python list after every nth element 【发布时间】:2015-09-11 11:31:25 【问题描述】:

假设我有一个这样的 Python 列表:

letters = ['a','b','c','d','e','f','g','h','i','j']

我想在每个第 n 个元素之后插入一个“x”,比如说该列表中的三个字符。结果应该是:

letters = ['a','b','c','x','d','e','f','x','g','h','i','x','j']

我知道我可以通过循环和插入来做到这一点。我真正在寻找的是一种 Python 方式,也许是单线?

【问题讨论】:

对于扩展方法,其中要插入的元素位于另一个列表中:Insert items from list to another list every n positions 【参考方案1】:

我有两个一体式衬垫。

给定:

>>> letters = ['a','b','c','d','e','f','g','h','i','j']

    使用enumerate获取索引,每3rd个字母添加'x'egmod(n, 3) == 2,然后连接成字符串和list()

    >>> list(''.join(l + 'x' * (n % 3 == 2) for n, l in enumerate(letters)))
    
    ['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j']
    

    但是作为@sancho.spoints out,如果任何元素有多个字母,这将不起作用。

    使用嵌套推导来展平列表列表(a),以 3 个为一组进行切片,如果列表末尾少于 3 个则添加 'x'

    >>> [x for y in (letters[i:i+3] + ['x'] * (i < len(letters) - 2) for
         i in xrange(0, len(letters), 3)) for x in y]
    
    ['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j']
    

(a) [item for subgroup in groups for item in subgroup] 将一个锯齿状的列表变平。

【讨论】:

如果元素不是单个字符,第一个不起作用。它以一个列表结束,每个元素都是一个字符(拆分字符串)。【参考方案2】:

试试这个

i = n
while i < len(letters):
    letters.insert(i, 'x')
    i += (n+1)

n 是在您要插入多少个元素之后'x'

这通过初始化变量i 并将其设置为等于n 来工作。然后设置一个while 循环,当i 小于letters 的长度时运行。然后在letters 的索引i 处插入'x'。然后您必须将n+1 的值添加到i。您必须使用n+1 而不仅仅是n 的原因是,当您向letters 插入一个元素时,它会将列表的长度扩大一倍。

n 为 3 的示例中尝试此操作,并且您想插入 'x',它看起来像这样

letters = ['a','b','c','d','e','f','g','h','i','j']
i = 3
while i < len(letters):
    letters.insert(i, 'x')
    i += 4

print letters

会打印出来

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

这是您的预期结果。

【讨论】:

这是不必要的二次方,在这种情况下可能很重要,也可能无关紧要。 @MikeGraham 这个二次方如何?我会认为它是线性的? (不是想反驳你,只是时间复杂度很差) @michaelpri insert() 本身采用O(n),在while 循环中使用使其成为二次方。这是wiki,显示了每个操作的时间复杂度。 @ozgur 哦,我不知道 insert 是 O(n)。谢谢:) @MikeGraham 在 OPs 的例子中,这是二次的并不重要,如果他们确实像这样保持简单,那就没关系了,但是随着列表越来越长,时间将开始发挥作用【参考方案3】:

虽然在for 循环中使用list.insert() 似乎更节省内存,但为了在一行中完成,您还可以在每个@ 分割的每个等分块的末尾附加给定值987654325@ 列表索引。

>>> from itertools import chain

>>> n = 2
>>> ele = 'x'
>>> lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

>>> list(chain(*[lst[i:i+n] + [ele] if len(lst[i:i+n]) == n else lst[i:i+n] for i in xrange(0, len(lst), n)]))
[0, 1, 'x', 2, 3, 'x', 4, 5, 'x', 6, 7, 'x', 8, 9, 'x', 10]

【讨论】:

+1 for itertools.chain 方法,使 [item for subgroup in group for item in subgroup] 的可迭代,这总是很难记住。在列表理解中使用 ternary 也是 +1;出于某种原因,我没有想到这一点,太棒了!【参考方案4】:

我想为每个项目添加一个新元素。

这个怎么样?

a=[2,4,6]
for b in range (0,len(a)):
    a.insert(b*2,1)

现在是

[1, 2, 1, 4, 1, 6]

【讨论】:

【参考方案5】:

一个非常简单的方法:

>>> letters = ['a','b','c','d','e','f','g','h','i','j']
>>> new_list = []
>>> n = 3
>>> for start_index in range(0, len(letters), n):
...     new_list.extend(letters[start_index:start_index+n])
...     new_list.append('x')
... 
>>> new_list.pop()
'x'
>>> new_list
['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j']

您还可以使用 itertools 文档中的 grouper 配方进行分块。

【讨论】:

如果new_list.pop() 弹出一个实际上应该存在的值怎么办? @Navith,它会弹出最后一个值,即我最后附加的 'x'【参考方案6】:

这是一个老话题,但它缺乏最简单、最“pythonic”的解决方案,imo。它只不过是对 Mark Mikofski 的 accepted answer 第 2 部分的扩展,可以说提高了可读性(因此使其更具 Python 风格)。

>>> letters = ['a','b','c','d','e','f','g','h','i','j']
>>> [el for y in [[el, 'x'] if idx % 3 == 2 else el for 
     idx, el in enumerate(letters)] for el in y]

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

【讨论】:

【参考方案7】:

值得一提的是简单的实现:

letters = ['a','b','c','d','e','f','g','h','i','j']

i = 3   #initial step
while i < len(letters):
    letters.insert(i,'x')
    i = i + 3 + 1  #increment step by one for every loop to account for the added element

它确实使用了基本的循环和插入,但它看起来也比单行示例更简单和舒适,恕我直言,它更符合Pythonish 的要求。

【讨论】:

【参考方案8】:

for 循环已经可以选择以某个值向上/向下步进:

letters = ['a','b','c','d','e','f','g','h','i','j']
n = 3

for i in range ( n, len(letters)+n, n+1 ):
  letters.insert ( i, 'X' )

print ( letters )

它不需要除法或模运算,只需要加法和一次大小计算。输出:

['a', 'b', 'c', 'X', 'd', 'e', 'f', 'X', 'g', 'h', 'i', 'X', 'j']

【讨论】:

【参考方案9】:

虽然Mark Mikofski 的answer 有效,但通过分配切片有一个更快的解决方案:

import string

# The longer the list the more speed up for list3
# letters = ['a','b','c','d','e','f','g','h','i','j']
letters = list(string.ascii_letters)
print("org:", letters)

# Use enumerate to get index, add 'x' every 3rd letter, eg: mod(n, 3) == 2, then concatenate into string and list() it.
list1 = list(''.join(l + 'x' * (n % 3 == 2) for n, l in enumerate(letters)))
print("list1:", list1)
%timeit list(''.join(l + 'x' * (n % 3 == 2) for n, l in enumerate(letters)))

# But as @sancho.s points out this doesn't work if any of the elements have more than one letter.
# Use nested comprehensions to flatten a list of lists(a), sliced in groups of 3 with 'x' added if less than 3 from end of list.
list2 = [x for y in (letters[i:i+3] + ['x'] * (i < len(letters) - 2) for i in range(0, len(letters), 3)) for x in y]
print("list2:", list2)
%timeit [x for y in (letters[i:i+3] + ['x'] * (i < len(letters) - 2) for i in range(0, len(letters), 3)) for x in y]

# Use list slice assignments
len_letters = len(letters)
len_plus_x = ll // 3
list3 = [None for _ in range(len_letters + len_plus_x)]
list3[::4] = letters[::3]
list3[2::4] = letters[2::3]
list3[1::4] = letters[1::3]
list3[3::4] = ['x' for _ in range(len_plus_x)]
print("list3:", list3)
%timeit ll = len(letters); lp = ll//3; new_letters = [None for _ in range(ll + lp)]; new_letters[::4] = letters[::3]; new_letters[2::4] = letters[2::3]; new_letters[1::4] = letters[1::3]; new_letters[3::4] = ['x' for _ in range(lp)]

产生(使用 jupyter notebook)

org: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
list1: ['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j', 'k', 'l', 'x', 'm', 'n', 'o', 'x', 'p', 'q', 'r', 'x', 's', 't', 'u', 'x', 'v', 'w', 'x', 'x', 'y', 'z', 'A', 'x', 'B', 'C', 'D', 'x', 'E', 'F', 'G', 'x', 'H', 'I', 'J', 'x', 'K', 'L', 'M', 'x', 'N', 'O', 'P', 'x', 'Q', 'R', 'S', 'x', 'T', 'U', 'V', 'x', 'W', 'X', 'Y', 'x', 'Z']
13 µs ± 1.09 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
list2: ['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j', 'k', 'l', 'x', 'm', 'n', 'o', 'x', 'p', 'q', 'r', 'x', 's', 't', 'u', 'x', 'v', 'w', 'x', 'x', 'y', 'z', 'A', 'x', 'B', 'C', 'D', 'x', 'E', 'F', 'G', 'x', 'H', 'I', 'J', 'x', 'K', 'L', 'M', 'x', 'N', 'O', 'P', 'x', 'Q', 'R', 'S', 'x', 'T', 'U', 'V', 'x', 'W', 'X', 'Y', 'x', 'Z']
13.7 µs ± 336 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
list3: ['a', 'b', 'c', 'x', 'd', 'e', 'f', 'x', 'g', 'h', 'i', 'x', 'j', 'k', 'l', 'x', 'm', 'n', 'o', 'x', 'p', 'q', 'r', 'x', 's', 't', 'u', 'x', 'v', 'w', 'x', 'x', 'y', 'z', 'A', 'x', 'B', 'C', 'D', 'x', 'E', 'F', 'G', 'x', 'H', 'I', 'J', 'x', 'K', 'L', 'M', 'x', 'N', 'O', 'P', 'x', 'Q', 'R', 'S', 'x', 'T', 'U', 'V', 'x', 'W', 'X', 'Y', 'x', 'Z']
4.86 µs ± 35.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

【讨论】:

【参考方案10】:
l = ['a','b','c','d','e','f','g','h','i','j']
[ l.insert(n+(n+1)*i, 'x') for i in range(len(l)/n) ]
print l

【讨论】:

以上是关于在每个第 n 个元素之后插入 Python 列表中的元素的主要内容,如果未能解决你的问题,请参考以下文章

如何拆分每个第N个元素的Python列表

hdu 6609 区间条件前缀和 + 二分

Python:计算具有不同长度的列表列表中第 n 个元素的平均值

无法将元素插入到列表的向量中

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

python插入排序算法总结