วิธีการตรวจสอบว่าองค์ประกอบอยู่ในอาร์เรย์


475

ใน Swift ฉันจะตรวจสอบองค์ประกอบที่มีอยู่ในอาร์เรย์ได้อย่างไร Xcode ไม่มีคำแนะนำใด ๆ สำหรับcontain, includeหรือhas, และการค้นหาอย่างรวดเร็วผ่านหนังสือไม่ปรากฏอะไรเลย มีความคิดวิธีตรวจสอบเรื่องนี้อย่างไร? ฉันรู้ว่ามีวิธีการfindที่ส่งกลับหมายเลขดัชนี แต่มีวิธีที่ส่งกลับแบบบูลเช่นทับทิม#include?หรือไม่?

ตัวอย่างของสิ่งที่ฉันต้องการ:

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

11
if find(elements, 5) != nil { }ยังไม่ดีพอ
Martin R

1
ฉันหวังว่าจะได้สิ่งที่สะอาดกว่า แต่มันก็ดูไม่ดี ฉันยังไม่พบอะไรในเอกสารหรือหนังสือเลย
ชำนาญการช่าง

คำตอบ:


860

Swift 2, 3, 4, 5:

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

contains()เป็นวิธีการขยายโพรโทคอลของSequenceType(สำหรับลำดับของEquatableองค์ประกอบ) และไม่ใช่วิธีสากลเช่นเดียวกับในรุ่นก่อนหน้า

หมายเหตุ:

Swift เวอร์ชันเก่า:

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

4
เอกสารใด ๆ เกี่ยวกับฟังก์ชั่นสากลประเภทนี้?
ริเวร่า

3
สิ่งนี้ควรจะใช้ได้หรือไม่หากแต่ละรายการในอาเรย์ (และรายการที่เรากำลังค้นหา) เป็นประเภท Dictionary <String, AnyObject> พยายามบรรลุ แต่ฉันได้รับข้อผิดพลาดในการรวบรวม
ppalancica

7
@ppalancica: สิ่งนี้ต้องการให้องค์ประกอบอาร์เรย์เป็นไปตามEquatableโปรโตคอล (ซึ่งDictionary<String, AnyObject>ไม่ได้) มีตัวแปรที่สองcontains()ซึ่งใช้เพรดิเคต (เปรียบเทียบstackoverflow.com/questions/29679486/ … ) บางทีคุณสามารถใช้สิ่งนั้นได้เช่นif contains(array, { $0 == dict } ) ...
Martin R

วิธีการค้นหาองค์ประกอบเฉพาะจากอาร์เรย์ทั่วไป? พูดว่า [AnyObject]?
Dhaval H. Nena

127

สำหรับผู้ที่มาที่นี่กำลังมองหาการค้นหาและลบวัตถุออกจากอาร์เรย์:

สวิฟท์ 1

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

สวิฟท์ 2

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

สวิฟท์ 3, 4

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

Swift 5.2

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

3
กรุณาตอบที่เกี่ยวข้องกับคำถาม คำถามนี้ถามเกี่ยวกับการหาองค์ประกอบในอาร์เรย์ไม่ใช่ลบหรืออัปเดต คุณสามารถตั้งคำถามแยกต่างหากและตอบคำถามเองได้
Tejas

60

ใช้ส่วนขยายนี้:

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

ใช้เป็น:

array.contains(1)

อัปเดตสำหรับ Swift 2/3

โปรดทราบว่าตั้งแต่ Swift 3 (หรือแม้กระทั่ง 2) ส่วนขยายไม่จำเป็นอีกต่อไปเนื่องจากcontainsฟังก์ชั่นทั่วโลกได้รับการสร้างขึ้นเป็นวิธีการขยายบนArrayคู่ซึ่งช่วยให้คุณทำอย่างใดอย่างหนึ่ง:

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

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

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

10
ค้นหาเร็วขึ้น
Jim Balter

1
ทั้งนี้ขึ้นอยู่กับสิ่งที่คุณคุ้นเคยแม้ว่าผู้ร่วมงานอาจรู้สึกง่ายและน่าจดจำมากขึ้น
Pirijan

4
คุณช่วยอธิบายไวยากรณ์ของคุณด้วยการทำลายมันได้หรือไม่? ฉันไม่เคยเห็นการจัดรูปแบบนี้มาก่อนและคุณมีเรื่องขั้นสูงมากมายเกิดขึ้นพร้อมกัน!
ผู้รุกราน

40

หากคุณกำลังตรวจสอบว่าอินสแตนซ์ของคลาสที่กำหนดเองหรือ structมีอยู่ในอาร์เรย์หรือไม่คุณจะต้องใช้โปรโตคอลEquatableก่อนจึงจะสามารถใช้ .contain (myObject)

ตัวอย่างเช่น:

struct Cup: Equatable {
    let filled:Bool
}

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

จากนั้นคุณสามารถทำได้:

cupArray.contains(myCup)

เคล็ดลับ : การแทนที่ == ควรอยู่ในระดับสากลไม่ใช่ในคลาส / โครงสร้างของคุณ


32

ฉันใช้ตัวกรอง

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

หากคุณต้องการคุณสามารถบีบอัดข้อมูลนั้นเป็น

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

หวังว่าจะช่วย


อัพเดทสำหรับ Swift 2

Hurray สำหรับการติดตั้งเริ่มต้น!

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

ฉันชอบโซลูชันตัวกรองเพราะคุณสามารถใช้กับทุกสิ่งได้ ตัวอย่างเช่นฉันกำลังย้ายรหัสบางส่วนที่วนไปวนมาและวนซ้ำพยายามดูว่ารายการมีรายการที่มีเขตข้อมูลหนึ่งในนั้นที่มีค่าสตริงอยู่หรือไม่ มันเป็นหนึ่งบรรทัดใน Swift โดยใช้ตัวกรองในฟิลด์นั้น
Maury Markowitz

ตัวกรองไม่มีประสิทธิภาพเพราะมันจะวนซ้ำทุกองค์ประกอบแทนที่จะกลับมาทันทีเมื่อพบองค์ประกอบ ควรใช้ find () แทน
Thorsten

19

(รวดเร็ว 3)

ตรวจสอบว่ามีองค์ประกอบอยู่ในอาร์เรย์หรือไม่ (ปฏิบัติตามเกณฑ์บางอย่าง) และหากเป็นเช่นนั้นให้ดำเนินการกับองค์ประกอบดังกล่าวก่อน

หากเจตนาคือ:

  1. ในการตรวจสอบว่ามีองค์ประกอบอยู่ในอาร์เรย์ (/ ปฏิบัติตามเกณฑ์บูลีนบางอย่างหรือไม่จำเป็นต้องทดสอบความเท่าเทียมกัน)
  2. และถ้าเป็นเช่นนั้นดำเนินการต่อและทำงานกับองค์ประกอบดังกล่าวเป็นครั้งแรก

จากนั้นทางเลือกที่จะcontains(_:)พิมพ์เขียวตามที่Sequenceเป็นfirst(where:)ของSequence:

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

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

ในตัวอย่างที่วางแผนไว้นี้การใช้งานของมันอาจดูไร้สาระ แต่ก็มีประโยชน์มากหากทำการสอบถามอาร์เรย์ขององค์ประกอบองค์ประกอบที่ไม่พื้นฐานสำหรับการมีอยู่ขององค์ประกอบใด ๆ ที่ตอบสนองเงื่อนไขบางประการ เช่น

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.

ดำเนินการใด ๆ ที่ถูกล่ามโซ่ใช้สามารถอยู่ในเกณฑ์ดีจะถูกแทนที่ด้วย.filter { ... some condition }.first first(where:)หลังแสดงให้เห็นถึงเจตนาที่ดีกว่าและมีข้อได้เปรียบด้านประสิทธิภาพมากกว่าอุปกรณ์ที่ไม่ขี้เกียจที่.filterเป็นไปได้เนื่องจากสิ่งเหล่านี้จะผ่านอาร์เรย์ทั้งหมดก่อนที่จะแยกองค์ประกอบแรก (เป็นไปได้) ผ่านตัวกรอง


ตรวจสอบว่ามีองค์ประกอบอยู่ในอาร์เรย์หรือไม่ (ทำตามเงื่อนไขบางอย่าง) และถ้าเป็นเช่นนั้นให้ลบองค์ประกอบดังกล่าวออกก่อน

ความคิดเห็นด้านล่างแบบสอบถาม:

ฉันจะลบออกfirstSuchElementจากอาร์เรย์ได้อย่างไร

กรณีการใช้งานที่คล้ายกับที่กล่าวข้างต้นคือการลบองค์ประกอบแรกที่ตอบสนองภาคที่กำหนด ในการทำเช่นนั้นindex(where:)วิธีการCollection(ซึ่งพร้อมใช้งานในการเก็บอาร์เรย์) อาจใช้เพื่อค้นหาดัชนีขององค์ประกอบแรกที่ตอบสนองเพรดิเคตซึ่งดัชนีสามารถใช้กับremove(at:)วิธีArrayการ (เป็นไปได้เนื่องจากมีอยู่) ลบองค์ประกอบนั้น

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

หรือหากคุณต้องการลบองค์ประกอบออกจากอาร์เรย์และใช้งานให้ใช้Optional: s เป็นmap(_:)วิธีการที่มีเงื่อนไข (สำหรับการ.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
}

โปรดทราบว่าในตัวอย่างที่วางแผนไว้ข้างต้นสมาชิกของอาร์เรย์ประเภทค่าง่าย ( Stringอินสแตนซ์) ดังนั้นการใช้คำกริยาที่จะหาสมาชิกได้รับค่อนข้างมากกว่าฆ่าที่เราอาจเพียงแค่การทดสอบเพื่อความเท่าเทียมกันใช้ง่ายindex(of:)วิธีการดังแสดงใน@ คำตอบ DogCoffee ของ . หากใช้วิธีการค้นหาและลบด้านบนกับPersonตัวอย่างอย่างไรก็ตามการใช้index(where:)กับภาคแสดงนั้นมีความเหมาะสม (เนื่องจากเราไม่ได้ทดสอบความเท่าเทียมกันอีกต่อไป


ฉันจะลบ FirstSuchElement ออกจากอาร์เรย์ได้อย่างไร
i6x86

@ i6x86 ขอบคุณสำหรับคำถาม ฉันอัปเดตคำตอบของฉันด้วยตัวอย่างของวิธีลบองค์ประกอบ (และวิธีลบและจับองค์ประกอบที่ลบออก)
dfri

14

วิธีที่ง่ายที่สุดในการทำเช่นนี้คือการใช้ตัวกรองในอาร์เรย์

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

resultจะมีองค์ประกอบที่พบหากมีอยู่และจะว่างเปล่าหากองค์ประกอบนั้นไม่มีอยู่ ดังนั้นเพียงแค่ตรวจสอบว่าresultว่างเปล่าจะบอกคุณว่าองค์ประกอบที่มีอยู่ในอาร์เรย์ ฉันจะใช้สิ่งต่อไปนี้:

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

ทางออกที่ดี ดังนั้นวิธีการนี้จะส่งกลับอาร์เรย์ อย่างไรก็ตามฉันใช้สิ่งนี้เพื่อค้นหา "id" ในแอปพลิเคชันของฉันมีลักษณะเฉพาะดังนั้นอาจมีเพียงผลลัพธ์เดียว มีวิธีคืนผลลัพธ์เพียง 1 รายการหรือไม่ ฉันใช้ผลลัพธ์ [0] ในตอนนี้
Dan Beaulieu

3
@DanBeaulieu การทำสิ่งที่let result = elements.filter { $0==5 }.firstควรทำให้สำเร็จในสิ่งที่คุณกำลังมองหา
davetw12


6

ในฐานะของ Swift 2.1 NSArrays มีcontainsObjectสิ่งที่สามารถใช้งานได้เช่น:

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

4
ที่จริงแล้วมีไว้สำหรับ NSArray ไม่ใช่อาเรย์ที่รวดเร็ว
Tycho Pandelaar

ใช่ แต่คุณสามารถแปลงอาร์เรย์ swift ของคุณชั่วคราวเป็น NSArray: ถ้าปล่อยให้ tempNSArrayForChecking = mySwiftArray เป็น NSArray หรือไม่ โดยที่ tempNSArrayForChecking.containObject (objectImCheckingFor) {// myArray มีวัตถุ}
Vitalii

4

ในกรณีที่มีใครพยายามหาว่าindexPathเป็นหนึ่งในคนที่เลือก (เช่นในUICollectionViewหรือUITableView cellForItemAtIndexPathฟังก์ชั่น):

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

4

แถว

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

ตรวจสอบองค์ประกอบที่มีอยู่

elements.contains(5) // true

รับดัชนีองค์ประกอบ

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

รับจำนวนองค์ประกอบ

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

3

นี่คือส่วนขยายเล็ก ๆ ของฉันฉันเพิ่งเขียนเพื่อตรวจสอบว่าอาร์เรย์ผู้รับมอบสิทธิ์ของฉันมีวัตถุผู้มอบหมายหรือไม่ ( Swift 2 ) :) นอกจากนี้ยังทำงานกับประเภทค่าเช่นเสน่ห์

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
    }
}

หากคุณมีความคิดวิธีเพิ่มประสิทธิภาพของรหัสนี้เพียงแค่แจ้งให้เราทราบ


2

หากผู้ใช้พบองค์ประกอบอาร์เรย์โดยเฉพาะแล้วใช้รหัสด้านล่างเช่นเดียวกับค่าจำนวนเต็ม

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

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

2

รวดเร็ว

หากคุณไม่ได้ใช้วัตถุคุณสามารถใช้รหัสนี้เพื่อบรรจุ

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

if elements.contains(50) {

   print("true")

}

หากคุณใช้ NSObject Class อย่างรวดเร็ว ตัวแปรนี้เป็นไปตามความต้องการของฉัน คุณสามารถปรับเปลี่ยนตามความต้องการของคุณ

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

นี่คือชนิดข้อมูลเดียวกัน

{ $0.user_id == cliectScreenSelectedObject.user_id }

ถ้าคุณต้องการประเภท AnyObject

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

สภาพสมบูรณ์

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

    cliectScreenSelected.append(cliectScreenSelectedObject)

    print("Object Added")

} else {

    print("Object already exists")

 }

1

แล้วการใช้ตารางแฮชกับงานแบบนี้ล่ะ?

ขั้นแรกให้สร้างฟังก์ชั่นทั่วไป "แฮชแมป" ซึ่งเป็นการขยายโพรโทคอลลำดับ

extension Sequence where Element: Hashable {

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

ส่วนขยายนี้จะทำงานได้ตราบใดที่รายการในอาร์เรย์สอดคล้องกับ Hashable เช่นจำนวนเต็มหรือสตริงนี่คือการใช้ ...

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

แต่สำหรับตอนนี้เราแค่มุ่งเน้นไปที่การตรวจสอบว่าองค์ประกอบอยู่ในอาร์เรย์หรือไม่

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 +
คุณสามารถตรวจสอบอินสแตนซ์ของคุณว่าเป็นอาร์เรย์ได้อย่างง่ายดายหรือไม่ด้วยฟังก์ชั่นต่อไปนี้

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

   return false
}

แม้ว่าคุณจะสามารถเข้าถึงได้ดังต่อไปนี้ คุณจะได้รับnilถ้าวัตถุจะไม่เป็นอาร์เรย์

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

   return nil
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.