Swift 3 Array, remove more than one item at once, with .remove(at: i)

て烟熏妆下的殇ゞ 提交于 2019-11-30 06:37:50

It's possible if the indexes are continuous using removeSubrange method. For example, if you would like to remove items at index 3 to 5:

myArray.removeSubrange(ClosedRange(uncheckedBounds: (lower: 3, upper: 5)))

For non-continuous indexes, I would recommend remove items with larger index to smaller one. There is no benefit I could think of of removing items "at the same time" in one-liner except the code could be shorter. You can do so with an extension method:

extension Array {
  mutating func remove(at indexes: [Int]) {
    for index in indexes.sorted(by: >) {
      remove(at: index)
    }
  }
}

Then:

myArray.remove(at: [3, 5, 8, 12])

UPDATE: using the solution above, you would need to ensure the indexes array does not contain duplicated indexes. Or you can avoid the duplicates as below:

extension Array {
    mutating func remove(at indexes: [Int]) {
        var lastIndex: Int? = nil
        for index in indexes.sorted(by: >) {
            guard lastIndex != index else {
                continue
            }
            remove(at: index)
            lastIndex = index
        }
    }
}


var myArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
myArray.remove(at: [5, 3, 5, 12]) // duplicated index 5
// result: [0, 1, 2, 4, 6, 7, 8, 9, 10, 11, 13] only 3 elements are removed

Remove elements using indexes of an array elements:

  1. Array of Strings and indexes

    let animals = ["cats", "dogs", "chimps", "moose", "squarrel", "cow"]
    let indexAnimals = [0, 3, 4]
    let arrayRemainingAnimals = animals
        .enumerated()
        .filter { !indexAnimals.contains($0.offset) }
        .map { $0.element }
    
    print(arrayRemainingAnimals)
    
    //result - ["dogs", "chimps", "cow"]
    
  2. Array of Integers and indexes

    var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
    let indexesToRemove = [3, 5, 8, 12]
    
    numbers = numbers
        .enumerated()
        .filter { !indexesToRemove.contains($0.offset) }
        .map { $0.element }
    
    print(numbers)
    
    //result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
    



Remove elements using element value of another array

  1. Arrays of integers

    var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
    let elementsTobeRemoved = [3, 5, 8, 12]
    let arrayResult = numbers.filter { element in
        return !elementsTobeRemoved.contains(element)
    }
    print(arrayResult)
    
    //result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
    
  2. Arrays of strings

    let arrayLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
    let arrayRemoveLetters = ["a", "e", "g", "h"]
    let arrayRemainingLetters = arrayLetters.filter {
        !arrayRemoveLetters.contains($0)
    }
    
    print(arrayRemainingLetters)
    
    //result - ["b", "c", "d", "f", "i"]
    

Swift 4

extension Array {

    mutating func remove(at indexs: [Int]) {
        guard !isEmpty else { return }
        let newIndexs = Set(indexs).sorted(by: >)
        newIndexs.forEach {
            guard $0 < count, $0 >= 0 else { return }
            remove(at: $0)  
        }
    }

}

var arr = ["a", "b", "c", "d", "e", "f"]

arr.remove(at: [2, 3, 1, 4])

result: ["a", "f"]

Simple and clear solution, just Array extension:

extension Array {

    mutating func remove(at indices: [Int]) {
        Set(indices)
            .sorted(by: >)
            .forEach { rmIndex in
                self.remove(at: rmIndex)
            }
    }
}
  • Set(indices) - ensures uniqueness
  • .sorted(by: >) - function removes elements from last to first, so during removal we are sure that indexes are proper

You can make a set of indexes you want to remove.

var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let indexSet = [3, 5, 8, 12]
indexSet.reversed().forEach{ array.remove(at: $0) }
print(array)

Output: [0, 1, 2, 4, 6, 7, 9, 10, 11]

In case indexes are continuous then use removeSubrange

array.removeSubrange(1...3) /// Will remove the elements from 1, 2 and 3 positions.

According to the NSMutableArray API I recommend to implement the indexes as IndexSet.

You just need to inverse the order.

extension Array {

    mutating func remove(at indexes: IndexSet) {
        indexes.reversed().forEach{ self.remove(at: $0) }
    }
}

Please see also this answer providing a more efficient algorithm.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!