Удаление объектов из массива на основе другого массива
У меня есть два массива:
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:
Массив строк и индексов
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"]
Массив целых чисел и индексов
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]
Удалить элементы, используя значение элемента другого массива
Массивы целых чисел
let arrayResult = numbers.filter { element in
return !indexesToRemove.contains(element)
}
print(arrayResult)
//result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
Массивы строк
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) }
}
}