Problem overview
The method moveToFront receives a to-do list items, an array of strings, and a number index. It returns the list with the item at index taken out of its place and put at index 0. The other items keep their order.
With items = ["wash", "shop", "cook", "read"] and index = 2, the item at index 2 is "cook". It moves to the front, and "wash" and "shop" shift one place to the right, giving ["cook", "wash", "shop", "read"]. When index is 0, the item is already at the front and nothing changes.
Approach
This is a remove followed by an insert. remove(at:) takes the item out and returns it, and the items behind it close the gap. insert(_:at:) then puts it at index 0, and everything else moves one place to the right. The items that were in front of it end up one place further back, and the ones behind it stay where they were: exactly the order the task asks for.
The index is always valid, from 0 to the length minus 1, so neither call can go out of range.
Step by step
- A function's parameters are constants in Swift, so
itemscannot be changed directly. Declare a new variable with the same name,var items = items. It is a copy, and from here on the name means the copy. - Call
remove(at: index)and store what it returns initem. - Call
insert(item, at: 0). The value comes first, then the position. - Return
items.
The solution in Swift
class Solution {
func moveToFront(_ items: [String], _ index: Int) -> [String] {
var items = items
let item = items.remove(at: index)
items.insert(item, at: 0)
return items
}
}
On the three examples it prints:
["cook", "wash", "shop", "read"]
["tea", "coffee"]
["call", "call", "pay", "walk"]
Language details
var items = itemsis allowed because the new variable lives inside the method body, a different scope from the parameter. Arrays are values, so it is a real copy: changing it never touches the array the caller passed in.- Without the copy,
items.remove(at: index)fails to compile withcannot use mutating member on immutable value: 'items' is a 'let' constant. - Index 0 works without a special case. The item comes out and goes straight back to the same place.
Testing
["a", "b", "c"]with index 2 gives["c", "a", "b"]: the last item jumps to the front.["x", "y", "z"]with index 1 gives["y", "x", "z"]: moving the second item swaps it with the first.["a"]with index 0 gives["a"].
After calling the method on a constant original = ["a", "b", "c"], printing original still shows ["a", "b", "c"]. The copy took all the changes.
Edge cases and common mistakes
- Duplicates. With
["call", "pay", "call", "walk"]and index 2, only the"call"at index 2 moves. The solution works by position, so the other"call"stays in line and the answer is["call", "call", "pay", "walk"]. - Inserting before removing. If you insert first, the list has one more item and the old item has a new index, so you would remove the wrong one.
- Reversing the arguments of insert. It is
insert(item, at: 0), notinsert(0, at: item). - Only one item. A list of one with index 0 comes back unchanged.
Cost
Removing from the middle and inserting at the front each shift items, so the work grows with the length of the list. With at most ten items that is no concern.
