cocobear
cocobear

Reputation: 425

What is the simplest way to swap each pair of adjoining chars in a string with Python?

I want to swap each pair of characters in a string. '2143' becomes '1234', 'badcfe' becomes 'abcdef'.

How can I do this in Python?

Upvotes: 31

Views: 159491

Answers (20)

Preetham
Preetham

Reputation: 11

To swap characters in a string a of position l and r

def swap(a, l, r):
    a = a[0:l] + a[r] + a[l+1:r] + a[l] + a[r+1:]
    return a

Example: swap("aaabcccdeee", 3, 7) returns "aaadcccbeee"

Upvotes: 1

Cieszkowski
Cieszkowski

Reputation: 128

While the above solutions do work, there is a very simple solution shall we say in "layman's" terms. Someone still learning python and string's can use the other answers but they don't really understand how they work or what each part of the code is doing without a full explanation by the poster as opposed to "this works". The following executes the swapping of every second character in a string and is easy for beginners to understand how it works.

It is simply iterating through the string (any length) by two's (starting from 0 and finding every second character) and then creating a new string (swapped_pair) by adding the current index + 1 (second character) and then the actual index (first character), e.g., index 1 is put at index 0 and then index 0 is put at index 1 and this repeats through iteration of string.

Also added code to ensure string is of even length as it only works for even length.

DrSanjay Bhakkad post above is also a good one that works for even or odd strings and is basically doing the same function as below.

string = "abcdefghijklmnopqrstuvwxyz123"

# use this prior to below iteration if string needs to be even but is possibly odd
if len(string) % 2 != 0:
    string = string[:-1]

# iteration to swap every second character in string
swapped_pair = ""
for i in range(0, len(string), 2):
    swapped_pair += (string[i + 1] + string[i])

# use this after above iteration for any even or odd length of strings
if len(swapped_pair) % 2 != 0:
    swapped_adj += swapped_pair[-1]

print(swapped_pair)

badcfehgjilknmporqtsvuxwzy21 # output if the "needs to be even" code used
badcfehgjilknmporqtsvuxwzy213 # output if the "even or odd" code used

Upvotes: 0

Gaurab Dawadi
Gaurab Dawadi

Reputation: 69

One of the easiest way to swap first two characters from a String is

inputString = '2134'

extractChar = inputString[0:2]
swapExtractedChar = extractChar[::-1]          """Reverse the order of string"""
swapFirstTwoChar = swapExtractedChar + inputString[2:]
 
# swapFirstTwoChar = inputString[0:2][::-1] + inputString[2:]     """For one line code"""

print(swapFirstTwoChar)

Upvotes: -1

Mad Physicist
Mad Physicist

Reputation: 114230

A bit late to the party, but there is actually a pretty simple way to do this:

The index sequence you are looking for can be expressed as the sum of two sequences:

 0  1  2  3 ...
+1 -1 +1 -1 ...

Both are easy to express. The first one is just range(N). A sequence that toggles for each i in that range is i % 2. You can adjust the toggle by scaling and offsetting it:

         i % 2      ->  0  1  0  1 ...
     1 - i % 2      ->  1  0  1  0 ...
2 * (1 - i % 2)     ->  2  0  2  0 ...
2 * (1 - i % 2) - 1 -> +1 -1 +1 -1 ...

The entire expression simplifies to i + 1 - 2 * (i % 2), which you can use to join the string almost directly:

result = ''.join(string[i + 1 - 2 * (i % 2)] for i in range(len(string)))

This will work only for an even-length string, so you can check for overruns using min:

N = len(string)
result = ''.join(string[min(i + 1 - 2 * (i % 2), N - 1)] for i in range(N))

Basically a one-liner, doesn't require any iterators beyond a range over the indices, and some very simple integer math.

Upvotes: 0

Duncan
Duncan

Reputation: 95622

The usual way to swap two items in Python is:

a, b = b, a

So it would seem to me that you would just do the same with an extended slice. However, it is slightly complicated because strings aren't mutable; so you have to convert to a list and then back to a string.
Therefore, I would do the following:

>>> s = 'badcfe'
>>> t = list(s)
>>> t[::2], t[1::2] = t[1::2], t[::2]
>>> ''.join(t)
'abcdef'

Upvotes: 24

Robotbugs
Robotbugs

Reputation: 4387

A more general answer... you can do any single pairwise swap with tuples or strings using this approach:

# item can be a string or tuple and swap can be a list or tuple of two
# indices to swap
def swap_items_by_copy(item, swap):
   s0 = min(swap)
   s1 = max(swap)
   if isinstance(item,str):
        return item[:s0]+item[s1]+item[s0+1:s1]+item[s0]+item[s1+1:]
   elif isinstance(item,tuple):
        return item[:s0]+(item[s1],)+item[s0+1:s1]+(item[s0],)+item[s1+1:]
   else:
        raise ValueError("Type not supported")

Then you can invoke it like this:

>>> swap_items_by_copy((1,2,3,4,5,6),(1,2))
(1, 3, 2, 4, 5, 6)
>>> swap_items_by_copy("hello",(1,2))
'hlelo'
>>> 

Thankfully python gives empty strings or tuples for the cases where the indices refer to non existent slices.

Upvotes: 1

user49505
user49505

Reputation: 1

#Think about how index works with string in Python,
>>> a = "123456"
>>> a[::-1]
'654321'

Upvotes: -3

DrSanjay Bhakkad
DrSanjay Bhakkad

Reputation: 19

#Works on even/odd size strings
str = '2143657'
newStr = ''
for i in range(len(str)//2):
    newStr += str[i*2+1] + str[i*2]
if len(str)%2 != 0:
    newStr += str[-1]
print(newStr)

Upvotes: -2

kevin
kevin

Reputation: 1

def revstr(a):
    b=''
    if len(a)%2==0:
        for i in range(0,len(a),2):
            b += a[i + 1] + a[i]
        a=b
    else:
        c=a[-1]
        for i in range(0,len(a)-1,2):
            b += a[i + 1] + a[i]
        b=b+a[-1]
        a=b
    return b
a=raw_input('enter a string')
n=revstr(a)
print n

Upvotes: 0

JohnMudd
JohnMudd

Reputation: 13813

>>> import ctypes
>>> s = 'abcdef'
>>> mutable = ctypes.create_string_buffer(s)
>>> for i in range(0,len(s),2):
>>>     mutable[i], mutable[i+1] = mutable[i+1], mutable[i]
>>> s = mutable.value
>>> print s
badcfe

Upvotes: 0

dansalmo
dansalmo

Reputation: 11686

One more way:

>>> s='123456'
>>> ''.join([''.join(el) for el in zip(s[1::2], s[0::2])])
'214365'

Upvotes: 0

cayhorstmann
cayhorstmann

Reputation: 3361

There is no need to make a list. The following works for even-length strings:

r = ''
for in in range(0, len(s), 2) :
  r += s[i + 1] + s[i]
s = r

Upvotes: 2

john doe
john doe

Reputation: 41

If performance or elegance is not an issue, and you just want clarity and have the job done then simply use this:

def swap(text, ch1, ch2):
    text = text.replace(ch2, '!',)
    text = text.replace(ch1, ch2)
    text = text.replace('!', ch1)
    return text

This allows you to swap or simply replace chars or substring. For example, to swap 'ab' <-> 'de' in a text:

_str = "abcdefabcdefabcdef"
print swap(_str, 'ab','de') #decabfdecabfdecabf

Upvotes: 4

Kabie
Kabie

Reputation: 10663

re.sub(r'(.)(.)',r"\2\1",'abcdef1234')

However re is a bit slow.

def swap(s):
    i=iter(s)
    while True:
        a,b=next(i),next(i)
        yield b
        yield a

''.join(swap("abcdef1234"))

Upvotes: 0

Paulo Scardine
Paulo Scardine

Reputation: 77251

oneliner:

>>> s = 'badcfe'
>>> ''.join([ s[x:x+2][::-1] for x in range(0, len(s), 2) ])
'abcdef'
  • s[x:x+2] returns string slice from x to x+2; it is safe for odd len(s).
  • [::-1] reverses the string in Python
  • range(0, len(s), 2) returns 0, 2, 4, 6 ... while x < len(s)

Upvotes: 30

Cristian Ciupitu
Cristian Ciupitu

Reputation: 20860

''.join(s[i+1]+s[i] for i in range(0, len(s), 2)) # 10.6 usec per loop

or

''.join(x+y for x, y in zip(s[1::2], s[::2])) # 10.3 usec per loop

or if the string can have an odd length:

''.join(x+y for x, y in itertools.izip_longest(s[1::2], s[::2], fillvalue=''))

Note that this won't work with old versions of Python (if I'm not mistaking older than 2.5).

The benchmark was run on python-2.7-8.fc14.1.x86_64 and a Core 2 Duo 6400 CPU with s='0123456789'*4.

Upvotes: 4

Lennart Regebro
Lennart Regebro

Reputation: 172209

Like so:

>>> s = "2143658709"
>>> ''.join([s[i+1] + s[i] for i in range(0, len(s), 2)])
'1234567890'

>>> s = "badcfe"
>>> ''.join([s[i+1] + s[i] for i in range(0, len(s), 2)])
'abcdef'

Upvotes: 0

Spacedman
Spacedman

Reputation: 94182

Loop over length of string by twos and swap:

def oddswap(st):
    s = list(st)
    for c in range(0,len(s),2):
        t=s[c]
        s[c]=s[c+1]
        s[c+1]=t

    return "".join(s)

giving:

>>> s
'foobar'
>>> oddswap(s)
'ofbora'

and fails on odd-length strings with an IndexError exception.

Upvotes: 2

FogleBird
FogleBird

Reputation: 76762

Here's one way...

>>> s = '2134'
>>> def swap(c, i, j):
...  c = list(c)
...  c[i], c[j] = c[j], c[i]
...  return ''.join(c)
...
>>> swap(s, 0, 1)
'1234'
>>>

Upvotes: 10

Spacedman
Spacedman

Reputation: 94182

Do you want the digits sorted? Or are you swapping odd/even indexed digits? Your example is totally unclear.

Sort:

s = '2143'
p=list(s)
p.sort()
s = "".join(p)

s is now '1234'. The trick is here that list(string) breaks it into characters.

Upvotes: 0

Related Questions