Удаление объектов из массива на основе другого массива

У меня есть два массива:

var arrayA = ["Mike", "James", "Stacey", "Steve"]
var arrayB = ["Steve", "Gemma", "James", "Lucy"]

Как вы можете видеть, James и Steve совпадают, и я хочу удалить их из arrayA. Как бы это написать?

Ответы

Ответ 1

Вот так:

var arrayA = ["Mike", "James", "Stacey", "Steve"]
var arrayB = ["Steve", "Gemma", "James", "Lucy"]
for word in arrayB {
    if let ix = find(arrayA, word) {
        arrayA.removeAtIndex(ix)
    }
}
// now arrayA is ["Mike", "Stacey"]

Ответ 2

@francesco-vadicamo ответ в Swift 2/3/4+

 arrayA = arrayA.filter { !arrayB.contains($0) }

Ответ 3

Самый простой способ - использовать новый контейнер Set (добавленный в Swift 1.2/Xcode 6.3):

var setA = Set(arrayA)
var setB = Set(arrayB)

// Return a set with all values contained in both A and B
let intersection = setA.intersect(setB) 

// Return a set with all values in A which are not contained in B
let diff = setA.subtract(setB)

Если вы хотите переназначить полученный набор на arrayA, просто создайте новый экземпляр, используя конструктор копирования, и назначьте его arrayA:

arrayA = Array(intersection)

Недостатком является то, что вам нужно создать 2 новых набора данных. Обратите внимание, что intersect не мутирует экземпляр, в который он вызывается, он просто возвращает новый набор.

Существуют аналогичные методы для добавления, вычитания и т.д., вы можете взглянуть на них

Ответ 4

Я согласен с ответом Антонио, однако для небольших вычитаний массива вы также можете использовать закрытие фильтра следующим образом:

let res = arrayA.filter { !contains(arrayB, $0) }

Ответ 5

матовые и freytag решения являются ТОЛЬКО те, которые учитывают дубликаты и должны получать больше + 1s, чем другие ответы.

Вот обновленная версия матового ответа для Swift 3.0:

var arrayA = ["Mike", "James", "Stacey", "Steve"]
var arrayB = ["Steve", "Gemma", "James", "Lucy"]
for word in arrayB {
    if let ix = arrayA.index(of: word) {
        arrayA.remove(at: ix)
    }
}

Ответ 6

Оригинальный ответ

Это также может быть реализовано как минус-функция:

func -<T:RangeReplaceableCollectionType where T.Generator.Element:Equatable>( lhs:T, rhs:T ) -> T {

    var lhs = lhs
    for element in rhs {
        if let index = lhs.indexOf(element) { lhs.removeAtIndex(index) }
    }

    return lhs
}

Теперь вы можете использовать

arrayA - arrayB

Обновленная реализация для Swift 5

func -<T: RangeReplaceableCollection>(lhs: T, rhs: T) -> T where T.Iterator.Element: Equatable {

    var lhs = lhs
    for element in rhs {
        if let index = lhs.firstIndex(of: element) { lhs.remove(at: index) }
    }

    return lhs
}

Ответ 7

Используя метод Array → Set → Array, упомянутый Антонио, и с удобством оператора, как указал freytag, я был очень доволен, используя это:

// Swift 3.x/4.x
func - <Element: Hashable>(lhs: [Element], rhs: [Element]) -> [Element]
{
    return Array(Set<Element>(lhs).subtracting(Set<Element>(rhs)))
}

Ответ 8

Удалить элементы с помощью массива indexes:

  1. Массив строк и индексов

    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. Массив целых чисел и индексов

    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]
    



Удалить элементы, используя значение элемента другого массива

  1. Массивы целых чисел

    let arrayResult = numbers.filter { element in
        return !indexesToRemove.contains(element)
    }
    print(arrayResult)
    
    //result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
    
  2. Массивы строк

    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"]
    

Ответ 9

Для небольших массивов я использую:

/* poormans sub for Arrays */

extension Array where Element: Equatable {

    static func -=(lhs: inout Array, rhs: Array) {

        rhs.forEach {
            if let indexOfhit = lhs.firstIndex(of: $0) {
                lhs.remove(at: indexOfhit)
            }
        }
    }

    static func -(lhs: Array, rhs: Array) -> Array {

        return lhs.filter { return !rhs.contains($0) }
    }
}