Swift array move function doesn't behave as you would expect - why?

Viewed 759

Recently Swift has a new method called move for Arrays. We can use it to tie in with Swiftui list drag and drop list moves. My challenge is that I don't understand how it works standalone and the docs in Apple are sparse about this. Here's a weird behavior I've noticed when I just play with this function.

var array = ["a", "b" ,"c", "d"]
print("before \(array)\n")
array = ["a", "b" ,"c", "d"]
array.move(fromOffsets: IndexSet(integer: 2), toOffset: 1)
print("after 2 -> 1 \(array)")
        
array = ["a", "b" ,"c", "d"]
array.move(fromOffsets: IndexSet(integer: 1), toOffset: 2)
print("after 1 -> 2 \(array)")

array = ["a", "b" ,"c", "d"]
array.move(fromOffsets: IndexSet(integer: 2), toOffset: 2)
print("after 2 -> 2 \(array)")

Results are:

after 2 -> 1 ["a", "c", "b", "d"]

after 1 -> 2 ["a", "b", "c", "d"]

after 2 -> 2 ["a", "b", "c", "d"]

I'm super confused about the 1->2 result ... how's that not change the array! It should be the same as the 2->1 shouldn't it?

Please help me understand.

2 Answers

I spent some time making ASCII art diagrams, so let's not put that time to waste.

Conceptually, I think of it as:

  • index points to the actual element
  • offset is the number of spaces travelled from the start of the array; essentially pointing at the gap between the elements

Thus, the algorithm is to:

  • get the item at specified index
  • determine the target offset (based on the array as it stands)
  • move that item into that offset

So, with your use cases:

["a", "b", "c", "d"]: moving from index 2 to offset 1: ["a", "c", "b", "d"]

|a|b|c|d| |a|b|c|d|
     v      ^
     |      |
     +------+

["a", "b", "c", "d"]: moving from index 1 to offset 2: ["a", "b", "c", "d"]

|a|b|c|d| |a|b|c|d|
   v          ^
   |          |
   +----------+

["a", "b", "c", "d"]: moving from index 2 to offset 2: ["a", "b", "c", "d"]

|a|b|c|d| |a|b|c|d|
     v        ^
     |        |
     +--------+

As you can see, nominating an offset that would place the element adjacent to itself would result in no apparent change to the array.

my understanding of the move operation is:

Moves all the elements at the specified offsets to the specified destination offset, preserving ordering.

The move is to just before destination, so the results you get are correct.

Related