Как определить, содержит ли один массив все элементы другого массива в Swift?
У меня есть 2 массива:
var list:Array<Int> = [1,2,3,4,5]
var findList:Array<Int> = [1,3,5]
Я хочу определить, содержит ли list
Array все элементы findList
.
Кстати, элементы могут быть String
или другим типом.
Как это сделать?
Я знаю, что Swift предоставляет метод contains
, который работает с одним элементом.
Ответы
Ответ 1
Вместо повторного использования массивов и выполнения фильтрации вы можете использовать NSSet
для выполнения всей работы для вас.
var list:Array<Int> = [1,2,3,4,5]
var findList:Array<Int> = [1,3,5]
let listSet = NSSet(array: list)
let findListSet = NSSet(array: findList)
let allElemtsEqual = findListSet.isSubsetOfSet(otherSet: listSet)
NSSet
намного быстрее, чем массивы при проверке, содержит ли он какой-либо объект. На самом деле это то, для чего он предназначен.
Изменить: Использование встроенного Swift Set
.
let list = [1,2,3,4,5]
let findList = [1,3,5]
let listSet = Set(list)
let findListSet = Set(findList)
let allElemsContained = findListSet.isSubsetOf(listSet)
Ответ 2
Рассмотрим следующий общий метод:
func arrayContainsArray<S : SequenceType where S.Generator.Element : Equatable>
(src:S, lookFor:S) -> Bool{
for v:S.Generator.Element in lookFor{
if contains(src, v) == false{
return false
}
}
return true
}
Преимущество - метод останавливается после 1-го отказа и не продолжается более findList
Испытания
var listAsInt:Array<Int> = [1,2,3,4,5]
var findListAsInt:Array<Int> = [1,3,5]
var result = arrayContainsArray(listAsInt, findListAsInt) // true
listAsInt:Array<Int> = [1,2,3,4,5]
findListAsInt:Array<Int> = [1,3,5,7,8,9]
result = arrayContainsArray(listAsInt, findListAsInt) // false
var listOfStr:Array<String> = ["aaa","bbb","ccc","ddd","eee"]
var findListOfStr:Array<String> = ["bbb","ccc","eee"]
result = arrayContainsArray(listOfStr, findListOfStr) // true
listOfStr:Array<String> = ["aaa","bbb","ccc","ddd","eee"]
findListOfStr:Array<String> = ["bbb","ccc","eee","sss","fff","ggg"]
result = arrayContainsArray(listOfStr, findListOfStr) // false
(проверено на Beta7)
Ответ 3
Вы можете использовать метод filter
для возврата всех элементов findList
, которые не находятся в list
:
let notFoundList = findList.filter( { contains(list, $0) == false } )
затем проверьте, равна ли длина возвращаемого массива нулевым:
let contained = notFoundList.count == 0
Обратите внимание, что его решение проходит весь массив findList
, поэтому он не останавливается, как только найден не содержащий элемент. Его следует использовать, если вы также хотите знать, какие элементы не содержатся.
Если вам просто нужно логическое утверждение о том, содержатся ли все элементы или нет, то решение, предоставленное Максимом Шустин, более эффективно.
Ответ 4
В Swift 3 вы можете написать это:
extension Array where Element: Equatable {
func contains(array: [Element]) -> Bool {
for item in array {
if !self.contains(item) { return false }
}
return true
}
}
Вы можете увидеть метод contains здесь
Это просто простое расширение, проверяющее, находится ли массив, который вы указываете, в текущем массиве (self)
Ответ 5
Прямо сейчас я бы использовал что-то вроде:
let result = list.reduce(true, { $0 ? contains(findList, $1) : $0 })
... но тогда я просто прочитал эту статью, что может смещать меня в сторону такого решения. Возможно, вы могли бы сделать это более эффективным, не сделав его полностью нечитаемым, но рано, и у меня не было кофе.
Ответ 6
Разверните Array
следующими способами:
extension Array {
func contains<T where T : Equatable>(obj: T) -> Bool {
return self.filter({$0 as? T == obj}).count > 0
}
func isEqualTo< T : Equatable> (comparingArray : [T]) -> Bool {
if self.count != comparingArray.count {
return false
}
for e in comparingArray {
if !self.contains(e){
return false
}
}
return true
}
}
Пример того, как вы можете использовать его следующим образом:
if selectedDates.isEqualTo(originalDates) {
//Arrays the same hide save button
} else {
//Arrays not the same, show Save & Discard Changes Button (if not shown)
}
Перейдите к @David Berry для метода .
Ответ 7
Это Ответ Максима Шустина обновлен для Swift 3:
func arrayContainsArray<S : Sequence>
(src:S, lookFor:S) -> Bool where S.Iterator.Element : Equatable{
for v:S.Iterator.Element in lookFor{
if src.contains(v) == false{
return false
}
}
return true
}
Ответ 8
var check = true
for i in findList {
if list.contains(i) {
check = check && true
} else {
check = false
}
}
Это работает отлично, если использовать.оператор не требуется.
Ответ 9
В качестве дополнения к Sequence.contains(element)
обработке нескольких элементов добавьте это расширение:
public extension Sequence where Element : Hashable {
func contains(_ elements: [Element]) -> Bool {
return Set(elements).isSubset(of:Set(self))
}
}
Б:
list.contains(findList)
Так как это использует Set
/Hashable
, он работает намного лучше, чем Equatable
альтернативы.