views:

125

answers:

5

Is there a pythonic way to insert an element into every 2nd element in a string?

I have a string: 'aabbccdd' and I want the end result to be 'aa-bb-cc-dd'.

I am not sure how I would go about doing that.

+8  A: 

Assume the string's length is always an even number,

>>> s = '12345678'
>>> t = iter(s)
>>> '-'.join(a+b for a,b in zip(t, t))
'12-34-56-78'

The t can also be eliminated with

>>> '-'.join(a+b for a,b in zip(s[::2], s[1::2]))
'12-34-56-78'

The algorithm is to group the string into pairs, then join them with the - character.

The code is written like this. Firstly, it is split into odd digits and even digits.

>>> s[::2], s[1::2]
('1357', '2468')

Then the zip function is used to combine them into an iterable of tuples.

>>> list( zip(s[::2], s[1::2]) )
[('1', '2'), ('3', '4'), ('5', '6'), ('7', '8')]

But tuples aren't what we want. This should be a list of strings. This is the purpose of the list comprehension

>>> [a+b for a,b in zip(s[::2], s[1::2])]
['12', '34', '56', '78']

Finally we use str.join() to combine the list.

>>> '-'.join(a+b for a,b in zip(s[::2], s[1::2]))
'12-34-56-78'

The first piece of code is the same idea, but consumes less memory if the string is long.

KennyTM
Can you explain the zip part? What is that doing?
root
What if length of s is odd?
Hamish Grubijan
@Ham: The last character will be gone.
KennyTM
@root: http://docs.python.org/py3k/library/functions.html#zip
KennyTM
Awesome thanks.
root
+7  A: 
>>> s = 'aabbccdd'
>>> '-'.join(s[i:i+2] for i in range(0, len(s), 2))
'aa-bb-cc-dd'
SilentGhost
What about sequences of odd length?
Hamish Grubijan
I consider this more pythonic than the zip voodoo in the aproved answer. The fact thet you don't need to use range(len(string)) in for loops in python, does not mean one have to go to invent crazy things just to avoid it.
jsbueno
@hamish: it keeps last character in and inserts a hyphen in front of it. Is it not a desired behaviour?
SilentGhost
A: 

This one-liner does the trick. It will drop the last character if your string has an odd number of characters.

"-".join([''.join(item) for item in zip(mystring1[::2],mystring1[1::2])])
chryss
SilentGhost's answer is better. But I liked trying out the zipping...
chryss
+1  A: 

If you want to preserve the last character if the string has an odd length, then you can modify KennyTM's answer to use itertools.izip_longest:

>>> s = "aabbccd"
>>> from itertools import izip_longest
>>> '-'.join(a+b for a,b in izip_longest(s[::2], s[1::2], fillvalue=""))
'aa-bb-cc-d'

or

>>> t = iter(s)
>>> '-'.join(a+b  for a,b in izip_longest(t, t, fillvalue=""))
'aa-bb-cc-d'
Dave Kirby
A: 

Here is one list comprehension way with conditional value depending of modulus of enumeration, odd last character will be in group alone:

for s  in ['aabbccdd','aabbccdde']:
    print(''.join([ char if not ind or ind % 2 else '-' + char
                    for ind,char in enumerate(s)
                    ]
                  )
          )
""" Output:
aa-bb-cc-dd
aa-bb-cc-dd-e
"""
Tony Veijalainen