0

Let say my string is as:

x = 'abcdefghi'

I want to reverse it in subsets of 3, so that my output is:

x = 'cbafedihg'

i.e. 0th index is swapped with 2nd index, 3rd index swapped with 5th, and so on.

Below is my code based on converting the string to list and swap the elements within the list:

string_list = list(x)
for i in range(len(string_list)/3):
    string_list[i*3], string_list[i*3+2] = string_list[i*3+2], string_list[i*3]

''.join(string_list)
# Output: 'cbafedihg'

I want to know what will be the most efficient and most pythonic way to achieve it.

Note: len(x)%3 will always be 0.

Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
  • Added the alternative approaches I could think of as an answer. I am still interested to know if there is any more efficient way to achieve it. – Moinuddin Quadri Sep 14 '16 at 08:20

3 Answers3

5

The above code can be written using string slicing and list comprehension as:

# Here x[i*3:i*3+3][::-1] will reverse the substring of 3 chars
>>> ''.join([x[i*3:i*3+3][::-1] for i in range(len(x)/3)])
'cbafedihg'

Based on the comment by Delgan, it could be further simplified using step as 3 with range itself as:

>>> ''.join(x[i:i+3][::-1] for i in range(0, len(x), 3))
'cbafedihg'
Community
  • 1
  • 1
Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
  • 2
    Other alternative: `''.join(x[i:i+3][::-1] for i in range(0, len(x), 3))` This presents the advantage of using generator comprehension instead of list comprehension, this seems more readable to me (less indice multiplications) and this is compatible with Python 3 as no floating division is done. – Delgan Sep 14 '16 at 08:25
  • @Delgan: Yes, that is also one nice solution. I missed that one. Definitely it is much cleaner compared to the 1st solution I mentioned here. – Moinuddin Quadri Sep 14 '16 at 08:29
  • @Delgan: Should I add it as edit with my answer, OR you will add it as an answer? Because, I think this will be helpful of the other users visiting SO in the future – Moinuddin Quadri Sep 14 '16 at 08:30
  • 1
    My alternative solution does not deserve its own response, an update of your answer seems to be a good solution. :) – Delgan Sep 14 '16 at 08:32
  • Updated it. I believe you deserve credit for that, so shared the link of your profile with it. Hope you won't mind :) – Moinuddin Quadri Sep 14 '16 at 08:38
  • It was not necessary but it is very kind of you, thank you! – Delgan Sep 14 '16 at 08:39
0

Another alternative to achieve this is to type-cast your string to list, then simply swap the elements of list using list slicing with step as 3, and join back the list of strings as:

>>> string_list = list(x)
>>> string_list[::3], string_list[2::3] = string_list[2::3], string_list[::3]
>>> ''.join(string_list)
'cbafedihg'
Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
0

Writing a function that is more readable and flexible?

def get_string(input_str, step=3):
    output = ""
    i = 0
    for _ in list(input_str):
        if i == len(input_str):
            return output
        elif i+step-1 >= len(input_str):
            output += input[len(input_str)-1:i-1:-1]
            return output
        else:
            output += input_str[i+step-1:i:-1] + input_str[i]
            i += step
    return output

And here comes the flexible part:

get_string("abcdefghi")
# Ouputs 'cbafedihg'
get_string("abcdefghi", 2)
# Outputs 'badcfehgi'
get_string("abcdefghi", 5)
# Outputs 'edcbaihgf'

Not to mention, if you want to add some more logic or change the logic, it is easier to change here.

thiruvenkadam
  • 4,170
  • 4
  • 27
  • 26