Home > Mobile >  Rearrange a list of strings
Rearrange a list of strings

Time:05-30

I want to rearrange or modify he sequence of elements (strings) in a list. This is the original list

['A', 'B', 'C', 'D', 'E', 'F', 'G']

I want to move E and F behind (or after?) B.

['A', 'B', 'E', 'F', 'C', 'D', 'G']
           ^^^  ^^^

The decision what to move comes from the user. There is no rule behind and no way to formulate that in an algorithm. In other words the action move something behind something other is input from the user; e.g. the user mark two elements with her/his mouse and drag an drop it behind another element.

My code works and is able to do this. But I wonder if there is a more efficient and pythonic way to do this. Maybe I missed some of Python's nice in-build features.

#!/usr/bin/env python3
# input data
original = list('ABCDEFG')

# move "EF" behind "B" (this is user input)
to_move = 'EF'
behind = 'B'

# expected result
rearanged = list('ABEFCDG')

# index for insertion
idx_behind = original.index(behind)

# each element to move
for c in reversed(to_move):  # "reverse!"
    # remove from original position
    original.remove(c)
    # add to new position
    original.insert(idx_behind   1, c)

# True
print(original == rearanged)

You can assume

  • Elements in original are unique.
  • to_move always exist in original.
  • behind always exist in original.
  • The elements in to_move are always adjacent.

Other example of possible input:

  • Move ['B'] behind F
  • Move ['A', 'B'] behind C

This is not possible:

  • Move ['A', 'F'] behind D

CodePudding user response:

  1. Don't use .remove when the goal is to erase from a specific position; though you may know what is at that position, .remove a) will search for it again, and b) remove the first occurrence, which is not necessarily the one you had in mind.

  2. Don't remove elements one at a time if you want to remove several consecutive elements; that's why slices exist, and why the del operator works the way that it does. Not only is it already harder to iterate when you can say what you want directly, but you have to watch out for the usual problems with modifying a list while iterating over it.

  3. Don't add elements one at a time if you want to add several elements that will be consecutive; instead, insert them all at once by slice assignment. Same reasons apply here.

  4. Especially don't try to interleave insertion and removal operations. That's far more complex than necessary, and could cause problems if the insertion location overlaps the source location.

Thus:

original = list('ABCDEFG')
start = original.index('E')
# grabbing two consecutive elements:
to_move = original[start:start 2]
# removing them:
del original[start:start 2]
# now figure out where to insert in that result:
insertion_point = original.index('B')   1
# and insert:
original[insertion_point:insertion_point] = to_move

CodePudding user response:

If it is just a small number of items you want to rearrange, just swap the relevant elements:

lst = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
lst[2], lst[4] = lst[4], lst[2]  # switch 'C' and 'E'
lst[3], lst[5] = lst[5], lst[3]  # switch 'D' and 'F'

lst
['A', 'B', 'E', 'F', 'C', 'D', 'G']
  • Related