Joining pairs of elements of a list [duplicate]
Asked Answered
G

7

85

I know that a list can be joined to make one long string as in:

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

Obviously this would output:

'abcd'

However, what I am trying to do is simply join the first and second strings in the list, then join the third and fourth and so on. In short, from the above example instead achieve an output of:

['ab', 'cd']

Is there any simple way to do this? I should probably also mention that the lengths of the strings in the list will be unpredictable, as will the number of strings within the list, though the number of strings will always be even. So the original list could just as well be:

['abcd', 'e', 'fg', 'hijklmn', 'opq', 'r'] 
Gaiety answered 1/5, 2011 at 20:3 Comment(3)
“I should probably also mention that the lengths of the strings in the list will be unpredictable” – So does the length matter? I.e. do you just want to join every pair of list elements, or do you actually want to look at the content and join as long as the resulting element stays below some special length limit?Marilyn
simply join every pair, i just thought that having not knowing the number of pairs could be a problemGaiety
Iterate over the list in pairs, and join each pair. See the linked duplicate.Lorrinelorry
S
81

You can use slice notation with steps:

>>> 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']

Same logic applies for lists too. String lenght doesn't matter, because you're simply adding two strings together.

Shorthand answered 1/5, 2011 at 20:9 Comment(3)
There is no doubt that kevpie's answer is far better. In this one, x[:::2] creates an object, x[1::2] creates another object, these creations being probably based on calculation of indexes under the hood, and a call to a function with these two objects passed as arguments is necessary before being able to obtain the successive pairs of elements that must be concatenated. While in kevpie's answer, there's just the creation of one iterator and then the iteration skips from element to element of the untouched list without having to take care of the indexes, and that's far more pythonic.Otero
@eyquem, using itertools.islice instead of [], eliminates the intermediate objects. But since both answers works on same conditions and returns same, they are both right. And zip(i[::2], i[1::2]) looks so sweet to me, so, why not? :)Shorthand
This only works on sequences, while @kevpie's answer is more general and works on any iterable.Electrodynamic
C
41

Use an iterator.

List comprehension:

>>> si = iter(['abcd', 'e', 'fg', 'hijklmn', 'opq', 'r'])
>>> [c+next(si, '') for c in si]
['abcde', 'fghijklmn', 'opqr']
  • Very efficient for memory usage.
  • Exactly one traversal of s

Generator expression:

>>> 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']
  • use as an iterator

Using map, str.__add__, iter

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

next(iterator[, default]) is available starting in Python 2.6

Chlorenchyma answered 1/5, 2011 at 20:40 Comment(1)
By far, the best answer. See my comment to utdemir's answer.Otero
P
5

just to be pythonic :-)

>>> 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']

in case the you want to be alarmed if the list length is odd you can try:

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

Best of Luck

Prolusion answered 7/4, 2014 at 9:42 Comment(0)
B
2

Without building temporary lists:

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

or:

>>> import itertools
>>> s = 'abcdefgh'
>>> si = iter(s)
>>> map(''.join, itertools.izip(si, si))
['ab', 'cd', 'ef', 'gh']
Bremsstrahlung answered 1/5, 2011 at 20:18 Comment(1)
Nice, but considering my code leaves me starting with the original list anyway, i think ill opt for utdmr's....thank you thoughGaiety
M
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']
Marilynnmarimba answered 1/5, 2011 at 20:12 Comment(0)
C
1

Well I would do it this way as I am no good with Regs..

CODE

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']  

Hope this helps :)

Contagium answered 16/11, 2013 at 7:0 Comment(0)
D
1

I came across this page interesting yesterday while wanting to solve a similar issue. I wanted to join items first in pairs using one string in between and then together using another string. Based on the code above I came up with the following function:

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)

This results in the following:

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

The filter step prevents the '' which is produced in case of an odd number of terms from putting a final pair_str at the end.

Deadbeat answered 1/6, 2022 at 11:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.