-1

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
martineau
  • 119,623
  • 25
  • 170
  • 301
buhtz
  • 10,774
  • 18
  • 76
  • 149
  • 4
    "I want to move E and F behind (or after?) B." What is the rule that tells you which letters to move? What is the rule that tells you where to move them? – Karl Knechtel May 30 '22 at 10:26
  • This seems wrong if some "to_move" value occurs before the "behind" value. – Kelly Bundy May 30 '22 at 10:38
  • 2
    "the user mark two elements with her/his mouse and drag an drop it behind another element." To be clear, will they always be *adjacent*? – Karl Knechtel May 30 '22 at 10:41
  • So "move B behind F" really shall produce ACDEFGB? Not ACDEFBG? – Kelly Bundy May 30 '22 at 10:51
  • @KellyBundy I don't understand your question. "move `B` behind `F`" should produce `ACDEFBG`. Why shouldn't it? – buhtz May 30 '22 at 10:54
  • Your code produces ACDEFGB, and you say your code works. – Kelly Bundy May 30 '22 at 10:55
  • @KellyBundy I am sure it doesn't. Of course I run it and the last line return a `True`. – buhtz May 30 '22 at 11:37
  • I don't know what you ran, but it wasn't *"move B behind F should produce ACDEFBG"*, as that gives you [`False`](https://tio.run/##dVHNTsQgEL7zFLP0UBqNjfFiTHqwuvUFvG/YMrslaYEArfXpK9Da9WLChZnvF8y377R6ejZ2WbJDOTpbnqUqUU1g1hXJQCozehDcc6KtvErFe6igl86z/LV@ez82H3lBAnDQEwI9NhTO2EklgNYUmO@kg3BGh3bVKojXpwSuIK9zsqHDpcmjDs4GW48CLLqx98Qit1xdUdxso2u92QYuznDRUT14eKkVkWI@7bK/qR8Skq3zREXedoA9Dqg8eJ0akKjUBq1gP6F1KNgWt3gByIBu4wMlAHFgMXW5WD3sVmC0kylJxOwBVihri43KhYi2Cr/@IayN2J86d/B4D21K/2lHJMZK5dntYyrYn6tYlh8). – Kelly Bundy May 31 '22 at 17:42

2 Answers2

2
  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
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
1

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']
buhtz
  • 10,774
  • 18
  • 76
  • 149
xnx
  • 24,509
  • 11
  • 70
  • 109