Removing elements at more than one index from an array?

Thank you for the small challenge, I hope I did not forget any corner case.

extension RangeReplaceableCollection where Index: Hashable {
  public mutating func removeAll<C>(at collection: C) -> Self where
    C: Collection,
    C.Element == Index
  {
    let indices = Set(collection)
    // Trap if number of elements in the set is different from the collection.
    // Trap if an index is out of range.
    precondition(
      indices.count == collection.count &&
      indices.allSatisfy(self.indices.contains)
    )
    // Create a new instance and reserve enough capacity to store all removed
    // elements.
    var result = Self.init()
    result.reserveCapacity(indices.count)
    // Remove the elements and fill the new collection.
    indices
      .lazy
      .sorted()
      .enumerated()
      .forEach { (offset, index) in
        let shiftedIndex = self.index(index, offsetBy: -offset)
        let element = remove(at: shiftedIndex)
        result.append(element) 
      }
    // Return the result collection.
    return result
  }
}

The whole trick is, you need to fix the indices for each iteration, which is quite easy since we know that each removal will decrease the count by one. With that knowledge we can simply offset every index by its negative enumerated offset. The indices must also be sorted before we do that.

1 Like