4

I need to reverse an interleaved string, means i have 2-pairs which shouldt get messed up like this:

>>> interleaved = "123456"

reversing

>>> print interleaved[::-1]
654321

but what i actually want is

563412

is there a string slice operation for this?

Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
Maximilian Körner
  • 846
  • 11
  • 31

3 Answers3

7

For even length strings this should do it:

>>> s = "123456"
>>> it = reversed(s)
>>> ''.join(next(it) + x for x in it)
'563412'

For odd length strings, you need to prepend the first character separately:

>>> s = "7123456"
>>> it = reversed(s)
>>> (s[0] if len(s)%2 else '') + ''.join(next(it) + x for x in it)
'7563412'

Using slicing and zip:

>>> s = "7123456"
>>> (s[0] if len(s)%2 else '') + ''.join(x+y for x, y in zip(s[-2::-2], s[::-2]))
'7563412'
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • Really creative, I liked your approach – avenet Jan 11 '14 at 12:04
  • Ashwini can you explain `next(it) + x for x in it` for me. I understand `next` and for loop expression but complete expression tricky to me. – Grijesh Chauhan Jan 11 '14 at 12:07
  • 1
    @GrijeshChauhan `reversed` returns an reversed iterator. Now during iteration the for-loop will call `next` on this iterator, but as we need the next item as well, so we call one more additional `next` inside the loop to get the next item. So, in the first iteration `x` will fetch `'6'` and `next(x)` will return `'5'` and so on... – Ashwini Chaudhary Jan 11 '14 at 12:10
  • I tried `>>> for x in it: next(it) + x` after reading your response in comment now it is clear. Thanks! – Grijesh Chauhan Jan 11 '14 at 12:18
  • Just make sure that either the `reversed` iterator knows about unicode strings, or that you are not in fact reversing unicode strings. Those are different beasts with combining characters and so on that needs to be handled differently than just reversing the sequence of all the individual characters. – Lasse V. Karlsen Jan 11 '14 at 12:25
4

The shortest way as far as I know would be to use a regex:

import re
''.join(re.findall('..?', '123456', flags=re.S)[::-1])
  • Input: '123456'
  • Output: '563412'

This also works for odd-length strings without having to implement separate logic for them.

Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
3

You can bring several ideas to split a string in pieces and then reverse each piece and reassemble (join) the list reversed too.

E.g. (using satomacoto answer in a not-so-readable way...)

''.join([a[::-1][i:i+2][::-1] for i in range(0, len(a), 2)]) 

or (using F.J. answer)

''.join(map(''.join, zip(*[iter(a)]*2))[::-1])

and so on. (Being a your string).

Community
  • 1
  • 1
ShinTakezou
  • 9,432
  • 1
  • 29
  • 39
  • What is the need of `[` `]` in `[iter(a)]` can you explain `(*[iter(a)]*2)` for me? – Grijesh Chauhan Jan 11 '14 at 13:01
  • 1
    In case some one have some question my doubt clear from here [How does `zip(*[iter(s)]*n)` work in Python?](http://stackoverflow.com/questions/2233204/how-does-zipitersn-work-in-python) – Grijesh Chauhan Jan 11 '14 at 13:30
  • I was pointing you also to [this SO Q/A](http://stackoverflow.com/questions/2921847/python-once-and-for-all-what-does-the-star-operator-mean-in-python) and [zip()](http://docs.python.org/2/library/functions.html#zip) but in fact the A you've found cover better the topic. – ShinTakezou Jan 11 '14 at 13:41
  • 1
    Actually my doubt could clear from edit part in linked question. any ways I want to thank you that I could know the trick from your answer. – Grijesh Chauhan Jan 11 '14 at 14:01
  • though the knowledge was already out there in SO, I've just unburied it for the OP's current question :) – ShinTakezou Jan 11 '14 at 14:06
  • 1
    yup, I am Python learner,today I am trying to explore from current question and all answers includes good tricks. – Grijesh Chauhan Jan 11 '14 at 14:13