Bir öğenin dizide olup olmadığını kontrol etme


475

Swift'te, bir dizide bir öğenin var olup olmadığını nasıl kontrol edebilirim? Xcode için herhangi bir öneri bulunmamaktadır contain, includeya hasve kitabın içinden bir hızlı arama hiçbir şey geldi. Bunun nasıl kontrol edileceği hakkında bir fikrin var mı? findDizin numarasını döndüren bir yöntem olduğunu biliyorum , ama ruby ​​gibi bir boole döndüren bir yöntem var #include?mı?

İhtiyacım olanın örneği:

var elements = [1,2,3,4,5]
if elements.contains(5) {
  //do something
}

11
if find(elements, 5) != nil { }yeterince iyi değil mi?
Martin R

1
Ben bile daha temiz bir şey umuyordum, ama iyi görünmüyor. Belgelerde veya kitapta henüz bir şey bulamadım.
jaredsmith

Yanıtlar:


860

Hızlı 2, 3, 4, 5:

let elements = [1, 2, 3, 4, 5]
if elements.contains(5) {
    print("yes")
}

contains()a, protokol uzantısı yöntemi ve SequenceType(dizileri için Equatableelemanları) ve daha önceki açıklamaları gibi genel bir yöntem.

Uyarılar:

Swift eski versiyonlar:

let elements = [1,2,3,4,5]
if contains(elements, 5) {
    println("yes")
}

4
Bu tür küresel işlevler hakkında herhangi bir belge var mı?
Rivera

3
Dizideki her öğe (ve aradığımız öğe) Dictionary <String, AnyObject> türündeyse, bu işe yarayacak mı? Bunu başarmaya çalışıyorum ama derleme zamanı hatası alıyorum.
ppalancica

7
@ppalancica: Bu, dizi öğelerinin Equatableprotokole uymasını gerektirir (ki bu Dictionary<String, AnyObject>uygun değildir). Bunun contains()bir yüklemi olan ikinci bir varyantı vardır (karşılaştırmak için stackoverflow.com/questions/29679486/… ), örneğin bunu kullanabilirsiniz, örneğinif contains(array, { $0 == dict } ) ...
Martin R

Jenerik diziden belirli bir eleman nasıl aranır? [AnyObject] mi diyorsun?
Dhaval H.Nena

127

Buraya gelenleri bulmak ve diziden bir nesneyi kaldırmak isteyenler için:

Hızlı 1

if let index = find(itemList, item) {
    itemList.removeAtIndex(index)
}

Hızlı 2

if let index = itemList.indexOf(item) {
    itemList.removeAtIndex(index)
}

Hızlı 3, 4

if let index = itemList.index(of: item) {
    itemList.remove(at: index)
}

Hızlı 5.2

if let index = itemList.firstIndex(of: item) {
    itemList.remove(at: index)
}

3
Lütfen soru ile ilgili cevap verin. Bu soru sadece dizideki bir öğeyi bulma, kaldırma veya güncelleme değil soruyor. Ayrı bir soru sorabilir ve kendiniz de cevaplayabilirsiniz.
Tejas

60

Bu uzantıyı kullanın:

extension Array {
    func contains<T where T : Equatable>(obj: T) -> Bool {
        return self.filter({$0 as? T == obj}).count > 0
    }
}

Kullanım şekli:

array.contains(1)

Swift 2/3 için güncellendi

Swift 3'ten (hatta 2) itibaren, global containsişlev, aşağıdakilerden Arraybirini yapmanızı sağlayan bir çift genişletme yöntemine dönüştürüldüğünden , uzantının artık gerekli olmadığını unutmayın:

let a = [ 1, 2, 3, 4 ]

a.contains(2)           // => true, only usable if Element : Equatable

a.contains { $0 < 1 }   // => false

10
bulmak daha hızlıdır.
Jim Balter

1
ne alışkın olduğunuza bağlı olarak,
.contains

4
Sözdizimini parçalayarak açıklayabilir misin? Bu biçimlendirmeyi daha önce hiç görmedim ve aynı anda birçok gelişmiş şey var!
Saldırgan

40

Bir dizide özel sınıf veya yapı örneğinin bulunup bulunmadığını kontrol ediyorsanız .contains (myObject) öğesini kullanabilmek için Equatable protokolünü uygulamanız gerekir .

Örneğin:

struct Cup: Equatable {
    let filled:Bool
}

static func ==(lhs:Cup, rhs:Cup) -> Bool { // Implement Equatable
    return lhs.filled == rhs.filled
}

o zaman şunları yapabilirsiniz:

cupArray.contains(myCup)

İpucu : == geçersiz kılma, sınıf / yapı içinde değil, küresel düzeyde olmalıdır


32

Filtre kullandım.

let results = elements.filter { el in el == 5 }
if results.count > 0 {
    // any matching items are in results
} else {
    // not found
}

İsterseniz bunu

if elements.filter({ el in el == 5 }).count > 0 {
}

Umarım yardımcı olur.


Swift 2 için güncelleme

Varsayılan uygulamalar için Yaşasın!

if elements.contains(5) {
    // any matching items are in results
} else {
    // not found
}

Filtre çözümünü seviyorum çünkü her türlü şey için kullanabilirsiniz. Örneğin, bir listenin zaten bir dize değeri içeren alanlarından biriyle bir öğeye sahip olup olmadığını görmeye çalışırken ilmekledi ve ilmekledi bazı kod taşıyordu. Bu var bir satır o sahada bir filtre kullanarak, Swift içinde.
Maury Markowitz

filtre verimsizdir çünkü eleman bulunduğunda hemen geri dönmek yerine her zaman tüm elemanların üzerinden geçer. Bunun yerine find () yöntemini kullanın.
Thorsten

19

(Hızlı 3)

Bir dizide bir öğenin var olup olmadığını kontrol edin (bazı kriterleri karşılayan) ve eğer öyleyse, bu tür ilk elemanla çalışmaya devam edin

Amaç:

  1. Bir öğenin bir dizide var olup olmadığını kontrol etmek (/ mutlaka eşitlik testi yerine bazı boole ölçütlerini karşılar),
  2. Ve eğer öyleyse, bu tür ilk unsurla devam edin ve çalışın,

Daha sonra bir alternatif contains(_:)blueprinted olarak Sequenceetmektir first(where:)arasında Sequence:

let elements = [1, 2, 3, 4, 5]

if let firstSuchElement = elements.first(where: { $0 == 4 }) {
    print(firstSuchElement) // 4
    // ...
}

Bu çelişkili örnekte kullanımı aptalca görünebilir, ancak temel olmayan eleman türlerinin dizilerini bir koşulu yerine getiren herhangi bir öğenin varlığı için sorgulamak çok yararlıdır. Örneğin

struct Person {
    let age: Int
    let name: String
    init(_ age: Int, _ name: String) {
        self.age = age
        self.name = name
    }
}

let persons = [Person(17, "Fred"),   Person(16, "Susan"),
               Person(19, "Hannah"), Person(18, "Sarah"),
               Person(23, "Sam"),    Person(18, "Jane")]

if let eligableDriver = persons.first(where: { $0.age >= 18 }) {
    print("\(eligableDriver.name) can possibly drive the rental car in Sweden.")
    // ...
} // Hannah can possibly drive the rental car in Sweden.

let daniel = Person(18, "Daniel")
if let sameAgeAsDaniel = persons.first(where: { $0.age == daniel.age }) {
    print("\(sameAgeAsDaniel.name) is the same age as \(daniel.name).")
    // ...
} // Sarah is the same age as Daniel.

Herhangi bir zincirleme işlem .filter { ... some condition }.firstuygun şekilde değiştirilebilir first(where:). İkincisi amacı daha iyi gösterir ve tembel olmayan cihazlara göre performans avantajlarına sahiptir .filter, çünkü bunlar filtreden geçen (olası) birinci elemanı çıkarmadan önce tam diziyi geçecektir.


Bir dizide bir öğenin var olup olmadığını kontrol edin (bazı kriterleri karşılayan) ve eğer öyleyse, bu tür ilk elemanı kaldırın

Sorguların altındaki bir yorum:

Diziden nasıl kaldırabilirim firstSuchElement?

Yukarıdakine benzer bir kullanım durumu, belirli bir yüklemi yerine getiren ilk elemanı çıkarmaktır . Bunu yapmak için, (dizi toplama için kolayca kullanılabilir) index(where:)yöntemi Collectionyüklemi yerine getiren ilk elemanın dizinini bulmak için kullanılabilir, daha sonra endeks, (olası; var olduğu göz önüne alındığında) remove(at:)yöntemi ile kullanılabilir Array(mümkün; o elemanı kaldır.

var elements = ["a", "b", "c", "d", "e", "a", "b", "c"]

if let indexOfFirstSuchElement = elements.index(where: { $0 == "c" }) {
    elements.remove(at: indexOfFirstSuchElement)
    print(elements) // ["a", "b", "d", "e", "a", "b", "c"]
}

Veya öğeyi diziden kaldırmak ve ile çalışmak isterseniz, kaldırılan öğeyi diziden kaldırmak ve yakalamak için (isteğe bağlı bir bağlama yan tümcesi içinde) sonucu koşullu olarak ( dönüş için ) uygulamak için Optional: s map(_:)yöntemini uygulayın. ..some(...)index(where:)index(where:)

var elements = ["a", "b", "c", "d", "e", "a", "b", "c"]

if let firstSuchElement = elements.index(where: { $0 == "c" })
    .map({ elements.remove(at: $0) }) {

    // if we enter here, the first such element have now been
    // remove from the array
    print(elements) // ["a", "b", "d", "e", "a", "b", "c"]

    // and we may work with it
    print(firstSuchElement) // c
}

Yukarıdaki örnekte dizi üyelerinin basit değer türleri ( Stringörnekler) olduğuna dikkat edin, bu nedenle belirli bir üyeyi bulmak için bir yüklem kullanmanın biraz fazla öldürme olduğunu unutmayın, çünkü @ DogCoffee'nin cevabındaindex(of:) gösterildiği gibi daha basit yöntemi kullanarak eşitliği test edebiliriz . Bununla birlikte, yukarıdaki bul ve kaldır yaklaşımını örneğe uyguluyorsanız, bir yüklem ile kullanmak uygundur (çünkü artık eşitliği test etmiyoruz, ancak verilen bir yüklemi yerine getirmek için).Personindex(where:)


FirstSuchElement öğesini diziden nasıl kaldırabilirim?
i6x86

@ i6x86 soru için teşekkürler. Cevabımı öğenin nasıl kaldırılacağına (ve ayrıca kaldırılan öğenin nasıl kaldırılacağına ve yakalanacağına) ilişkin bir örnekle güncelledim.
dfri

14

Bunu yapmanın en basit yolu dizide filtre kullanmaktır.

let result = elements.filter { $0==5 }

resultvarsa bulunan öğeye sahip olur ve öğe yoksa boş olur. Bu nedenle result, boş olup olmadığını kontrol etmek, öğenin dizide olup olmadığını size söyleyecektir. Aşağıdakileri kullanırdım:

if result.isEmpty {
    // element does not exist in array
} else {
    // element exists
}

harika bir çözüm. yani bu yöntem bir dizi döndürür. Ancak, bunu bir "id" aramak için kullanıyorum. Benim uygulamada d benzersizdir, bu yüzden sadece bir sonuç olabilir. Sadece 1 sonuç döndürmenin bir yolu var mı? Şimdilik sonuç [0] kullanıyorum
Dan Beaulieu

3
@DanBeaulieu Böyle bir şey yapmak aradığınızı başarmalıdır let result = elements.filter { $0==5 }.first.
davetw12

7

Hızlı 4/5

Bunu başarmanın başka bir yolu da filtre işlevidir.

var elements = [1,2,3,4,5]
if let object = elements.filter({ $0 == 5 }).first {
    print("found")
} else {
    print("not found")
}

6

Swift 2.1'den itibaren NSArrays containsObjectşu şekilde kullanılabilir:

if myArray.containsObject(objectImCheckingFor){
    //myArray has the objectImCheckingFor
}

4
Aslında bu bir NSArray için. Hızlı bir dizi değil
Tycho Pandelaar

Evet, ancak geçici dizinizi geçici olarak NSArray'e dönüştürebilirsiniz: eğer izin ver tempNSArrayForChecking = mySwiftArray NSArray olarak? Burada tempNSArrayForChecking.containsObject (objectImCheckingFor) {// myArray nesneye sahiptir}
Vitalii

4

Herhangi birinin an'in indexPathseçilenler arasında olup olmadığını bulmaya çalışması durumunda (a UICollectionViewveya UITableView cellForItemAtIndexPathfonksiyonlarda olduğu gibi):

    var isSelectedItem = false
    if let selectedIndexPaths = collectionView.indexPathsForSelectedItems() as? [NSIndexPath]{
        if contains(selectedIndexPaths, indexPath) {
            isSelectedItem = true
        }
    }

4

Dizi

let elements = [1, 2, 3, 4, 5, 5]

Elemanların varlığını kontrol edin

elements.contains(5) // true

Öğeler dizinini al

elements.firstIndex(of: 5) // 4
elements.firstIndex(of: 10) // nil

Öğe sayısını alın

let results = elements.filter { element in element == 5 }
results.count // 2

3

İşte benim delege dizisi bir temsilci nesnesi içerip içermediğini kontrol etmek için yazdım küçük uzantısı ( Swift 2 ). :) Ayrıca bir cazibe gibi değer türleri ile çalışır.

extension Array
{
    func containsObject(object: Any) -> Bool
    {
        if let anObject: AnyObject = object as? AnyObject
        {
            for obj in self
            {
                if let anObj: AnyObject = obj as? AnyObject
                {
                    if anObj === anObject { return true }
                }
            }
        }
        return false
    }
}

Bu kodu nasıl optimize edeceğiniz hakkında bir fikriniz varsa, bana bildirin.


2

kullanıcı belirli dizi öğelerini bulursa tamsayı değeriyle aynı kodu kullanır.

var arrelemnts = ["sachin", "test", "test1", "test3"]

 if arrelemnts.contains("test"){
    print("found")   }else{
    print("not found")   }

2

hızlı

Nesne kullanmıyorsanız, içerdiği bu kodu kullanıcı için kullanabilirsiniz.

let elements = [ 10, 20, 30, 40, 50]

if elements.contains(50) {

   print("true")

}

NSObject Class'ı hızlı bir şekilde kullanıyorsanız. Bu değişkenler benim gereksinimime göre. İhtiyaçlarınız için değiştirebilirsiniz.

var cliectScreenList = [ATModelLeadInfo]()
var cliectScreenSelectedObject: ATModelLeadInfo!

Bu aynı veri türü içindir.

{ $0.user_id == cliectScreenSelectedObject.user_id }

AnyObject türünü istiyorsanız.

{ "\($0.user_id)" == "\(cliectScreenSelectedObject.user_id)" }

Tam koşul

if cliectScreenSelected.contains( { $0.user_id == cliectScreenSelectedObject.user_id } ) == false {

    cliectScreenSelected.append(cliectScreenSelectedObject)

    print("Object Added")

} else {

    print("Object already exists")

 }

1

iş için bir karma tablo kullanmaya ne dersiniz?

ilk olarak, bir "hash map" jenerik fonksiyonu oluşturmak ve Sekans protokolünü genişletmek.

extension Sequence where Element: Hashable {

    func hashMap() -> [Element: Int] {
        var dict: [Element: Int] = [:]
        for (i, value) in self.enumerated() {
            dict[value] = i
        }
        return dict
    }
}

Bu uzantı, dizideki öğeler tamsayılar veya dizeler gibi Hashable'a uyduğu sürece işe yarar ...

let numbers = Array(0...50) 
let hashMappedNumbers = numbers.hashMap()

let numToDetect = 35

let indexOfnumToDetect = hashMappedNumbers[numToDetect] // returns the index of the item and if all the elements in the array are different, it will work to get the index of the object!

print(indexOfnumToDetect) // prints 35

Ancak şimdilik, öğenin dizide olup olmadığını kontrol edelim.

let numExists = indexOfnumToDetect != nil // if the key does not exist 
means the number is not contained in the collection.

print(numExists) // prints true

0

Swift 4.2 +
Aşağıdaki işlevle örneğinizin bir dizi olup olmadığını kolayca doğrulayabilirsiniz.

func verifyIsObjectOfAnArray<T>(_ object: T) -> Bool {
   if let _ = object as? [T] {
      return true
   }

   return false
}

Hatta ona aşağıdaki gibi erişebilirsiniz. nilNesne bir dizi olmazsa alırsınız .

func verifyIsObjectOfAnArray<T>(_ object: T) -> [T]? {
   if let array = object as? [T] {
      return array
   }

   return nil
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.