连接列表中成对的元素

85

我知道可以将列表连接成一个长字符串,例如:

x = ['a', 'b', 'c', 'd']
print ''.join(x)

很明显,这将输出:

'abcd'

然而,我想做的就是简单地将列表中的第一个字符串和第二个字符串连接起来,然后将第三个和第四个字符串连接在一起,以此类推。简而言之,从上面的示例中实现以下输出:

['ab', 'cd']

有没有简单的方法来做到这一点?我还应该提到,列表中字符串的长度是不可预测的,列表中字符串的数量也是不可预测的,尽管字符串的数量始终是偶数。所以原始列表也可能是:

['abcd', 'e', 'fg', 'hijklmn', 'opq', 'r'] 

“我应该也提一下列表中字符串的长度是不可预测的” - 所以长度很重要吗?即,您只想连接列表元素的每一对,还是您实际上想查看内容并连接,只要结果元素保持在某个特定长度限制以下? - poke
只需将每对连接起来,我只是认为不知道成对数量可能会成为一个问题。 - John
迭代列表中的一对,然后连接每一对。请参见链接的重复项。 - Karl Knechtel
7个回答

81
你可以使用切片符号来指定步骤大小:
>>> x = "abcdefghijklm"
>>> x[0::2] #0. 2. 4...
'acegikm'
>>> x[1::2] #1. 3. 5 ..
'bdfhjl'
>>> [i+j for i,j in zip(x[::2], x[1::2])] # zip makes (0,1),(2,3) ...
['ab', 'cd', 'ef', 'gh', 'ij', 'kl']

同样的逻辑也适用于列表。字符串长度并不重要,因为你只是简单地将两个字符串相加。


1
毫无疑问,kevpie的答案更好。在这个答案中,“x [:::2]”创建一个对象,“x [1 :: 2]”创建另一个对象,这些创建可能基于底层索引计算,并且需要调用一个函数,将这两个对象作为参数传递,才能获得必须连接的连续对元素。而在kevpie的答案中,只需创建一个迭代器,然后迭代跳过未经处理的列表的元素,而无需关心索引,这更符合Python的风格。 - eyquem
@eyquem,使用itertools.islice代替[]可以消除中间对象。但由于两个答案在相同条件下都能工作并返回相同结果,它们都是正确的。而且zip(i[::2], i[1::2])看起来很棒,所以为什么不用呢? :) - utdemir
这仅适用于序列,而@kevpie的答案更通用,适用于任何可迭代对象 - Kos

41

使用迭代器。

列表推导式:

>>> si = iter(['abcd', 'e', 'fg', 'hijklmn', 'opq', 'r'])
>>> [c+next(si, '') for c in si]
['abcde', 'fghijklmn', 'opqr']
  • 内存使用非常高效。
  • 仅需要遍历一次 s。

生成器表达式:

>>> si = iter(['abcd', 'e', 'fg', 'hijklmn', 'opq', 'r'])
>>> pair_iter = (c+next(si, '') for c in si)
>>> pair_iter # can be used in a for loop
<generator object at 0x4ccaa8>
>>> list(pair_iter) 
['abcde', 'fghijklmn', 'opqr']
  • 用作迭代器

使用map、str.__add__和iter函数

>>> si = iter(['abcd', 'e', 'fg', 'hijklmn', 'opq', 'r'])
>>> map(str.__add__, si, si)
['abcde', 'fghijklmn', 'opqr']

next(iterator[, default]) 是从 Python 2.6 开始可用的。


2
到目前为止,这是最好的答案。请查看我对utdemir答案的评论。 - eyquem

5

只是为了符合Python的编码风格 :-)

>>> x = ['a1sd','23df','aaa','ccc','rrrr', 'ssss', 'e', '']
>>> [x[i] + x[i+1] for i in range(0,len(x),2)]
['a1sd23df', 'aaaccc', 'rrrrssss', 'e']

如果您希望在列表长度为奇数时收到警报,可以尝试以下方法:

[x[i] + x[i+1] if not len(x) %2 else 'odd index' for i in range(0,len(x),2)]

祝你好运


2

不需要建立临时列表:

>>> import itertools
>>> s = 'abcdefgh'
>>> si = iter(s)
>>> [''.join(each) for each in itertools.izip(si, si)]
['ab', 'cd', 'ef', 'gh']

或者:

>>> import itertools
>>> s = 'abcdefgh'
>>> si = iter(s)
>>> map(''.join, itertools.izip(si, si))
['ab', 'cd', 'ef', 'gh']

不错,但考虑到我的代码最终还是要从原始列表开始,我想我会选择utdmr的...谢谢你的建议。 - John

1
昨天我在想要解决一个类似的问题时,偶然发现了这个有趣的页面。我想用一个字符串将项目首先成对连接起来,然后再用另一个字符串将它们连接在一起。根据上面的代码,我编写了以下函数:
def pairs(params,pair_str, join_str):
"""Complex string join where items are first joined in pairs
"""
terms = iter(params)
pairs = [pair_str.join(filter(len, [term, next(terms, '')])) for term in terms]
return join_str.join(pairs)

这将导致以下结果:

a = ['1','2','3','4','5','6','7','8','9']
print(pairs(a, ' plus ', ' and '))
>>1 plus 2 and 3 plus 4 and 5 plus 6 and 7 plus 8 and 9

过滤步骤可以防止在项数为奇数的情况下产生 '',从而避免在末尾放置最后一个 pair_str。


1
>>> lst =  ['abcd', 'e', 'fg', 'hijklmn', 'opq', 'r'] 
>>> print [lst[2*i]+lst[2*i+1] for i in range(len(lst)/2)]
['abcde', 'fghijklmn', 'opqr']

1
我会按照以下方式进行操作,因为我不擅长正则表达式:

代码

t = '1. eat, food\n\
7am\n\
2. brush, teeth\n\
8am\n\
3. crack, eggs\n\
1pm'.splitlines()

print [i+j for i,j in zip(t[::2],t[1::2])]

output:

['1. eat, food   7am', '2. brush, teeth   8am', '3. crack, eggs   1pm']  

希望这有所帮助 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接