removeObjectsAtIndexes for Swift arrays

前端 未结 14 1183
长情又很酷
长情又很酷 2020-11-30 12:34

What is a Swift array equivalent to NSMutableArray\'s -removeObjectsAtIndexes:? Removing each index one by one doesn\'t work, as remaining indexes

相关标签:
14条回答
  • 2020-11-30 12:50

    Here is the solution I currently use:

    extension Array {
        mutating func removeObjectAtIndexes(indexes: [Int]) {
            var indexSet = NSMutableIndexSet()
    
            for index in indexes {
                indexSet.addIndex(index)
            }
    
            indexSet.enumerateIndexesWithOptions(.Reverse) {
                self.removeAtIndex($0.0)
                return
            }
        }
    
        mutating func removeObjectAtIndexes(indexes: Int...) {
            removeObjectAtIndexes(indexes)
        }
    }
    
    0 讨论(0)
  • 2020-11-30 12:52

    Swift 4 attempt

    extension Array {
    
        mutating func removeAtIndexes(indexes: IndexSet) {
            var i:Index? = indexes.last
            while i != nil {
                self.remove(at: i!)
                i = indexes.integerLessThan(i!)
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-30 12:53

    Based upon Kent's solution but updated for Swift 3

    extension Array {
        mutating func remove(indices: IndexSet) {
            self = self.enumerated().filter { !indices.contains($0.offset) }.map { $0.element }
        }
    }
    
    0 讨论(0)
  • 2020-11-30 12:56

    I needed this for working with a NSTableview. This is what I use.

    extension Array{
    mutating func removeElementsAtIndexes(indexset:NSIndexSet){
        self = self.enumerate().filter({!indexset.containsIndex($0.index)}).map({$0.element})
        }
    }
    
    0 讨论(0)
  • 2020-11-30 13:00

    I like a pure Swift solution, i.e. without resorting to NSIndexSet:

    extension Array {
        mutating func removeAtIndexes (ixs:[Int]) -> () {
            for i in ixs.sorted(>) {
                self.removeAtIndex(i)
            }
        }
    }
    

    EDIT In Swift 4 that would be:

    extension Array {
        mutating func remove (at ixs:[Int]) -> () {
            for i in ixs.sorted(by: >) {
                self.remove(at:i)
            }
        }
    }
    

    But years after I wrote that answer, the WWDC 2018 Embracing Algorithms video points out the flaw: it's O(n2), because remove(at:) itself has to loop through the array.

    According to that video, Swift 4.2 removeAll(where:) is efficient because it uses half-stable partitioning. So we could write something like this:

    extension Array {
        mutating func remove(at set:IndexSet) {
            var arr = Swift.Array(self.enumerated())
            arr.removeAll{set.contains($0.offset)}
            self = arr.map{$0.element}
        }
    }
    

    My tests show that despite the repeated contains, that's 100 times faster. However, @vadian's approach is 10 times faster than that, because he unrolls contains by ingeniously walking the index set at the same time he walks the array (using half-stable partitioning).

    0 讨论(0)
  • 2020-11-30 13:00

    Updated for Swift 2.0:

    extension Array {
        mutating func removeAtIndices(incs: [Int]) {
            incs.sort(>).map { removeAtIndex($0) }
        }
    }
    

    Use forEach instead of map if it gives a warning that the result isn't used (Since Swift 2 beta 6 I think)

    EDIT: Super generic lazy solution:

    extension RangeReplaceableCollectionType where Index : Comparable {
        mutating func removeAtIndices<S : SequenceType where S.Generator.Element == Index>(indices: S) {
            indices.sort().lazy.reverse().forEach{ removeAtIndex($0) }
        }
    }
    
    0 讨论(0)
提交回复
热议问题