Làm thế nào để kiểm tra nếu một phần tử nằm trong một mảng


475

Trong Swift, làm cách nào tôi có thể kiểm tra xem một phần tử có tồn tại trong một mảng không? Xcode không có bất kỳ đề xuất nào cho contain, includehoặc has, và tìm kiếm nhanh thông qua cuốn sách không có gì. Bất kỳ ý tưởng làm thế nào để kiểm tra này? Tôi biết rằng có một phương thức findtrả về số chỉ mục, nhưng có phương thức nào trả về giá trị boolean như ruby #include?không?

Ví dụ về những gì tôi cần:

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

11
if find(elements, 5) != nil { }không đủ tốt
Martin R

1
Tôi đã hy vọng cho một cái gì đó thậm chí sạch hơn, nhưng nó không nhìn tốt. Tôi chưa tìm thấy bất cứ điều gì trong tài liệu hoặc cuốn sách.
jaredsmith

Câu trả lời:


860

Swift 2, 3, 4, 5:

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

contains()là một phương thức mở rộng giao thức của SequenceType(cho chuỗi các Equatablephần tử) chứ không phải là phương thức toàn cầu như trong các bản phát hành trước đó.

Nhận xét:

Swift phiên bản cũ hơn:

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

4
Bất kỳ tài liệu về loại chức năng toàn cầu này?
Rivera

3
Đây có phải là hoạt động nếu mỗi mục bên trong mảng (và mục chúng tôi đang tìm kiếm) thuộc loại Từ điển <String, AnyObject>? Cố gắng để đạt được điều đó nhưng tôi nhận được lỗi thời gian biên dịch.
ppalancica

7
@ppalancica: Điều này đòi hỏi các thành phần mảng phải tuân thủ Equatablegiao thức ( Dictionary<String, AnyObject>không có). Có một biến thể thứ hai của contains()mà phải mất một vị ngữ (so sánh stackoverflow.com/questions/29679486/... ) có lẽ bạn có thể sử dụng, ví dụ nhưif contains(array, { $0 == dict } ) ...
Martin R

Làm thế nào để tìm kiếm phần tử cụ thể từ mảng chung? nói [AnyObject]?
Dhaval H. Nena

127

Đối với những người đến đây để tìm kiếm và xóa một đối tượng khỏi một mảng:

Swift 1

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

Swift 2

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

Swift 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
Hãy trả lời liên quan đến câu hỏi. Câu hỏi này chỉ hỏi về việc tìm một phần tử trong mảng, không loại bỏ hoặc cập nhật nó. Bạn có thể đưa ra một câu hỏi riêng biệt và tự trả lời nó.
Tejas

60

Sử dụng tiện ích mở rộng này:

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

Sử dụng như là:

array.contains(1)

Cập nhật cho Swift 2/3

Lưu ý rằng kể từ Swift 3 (hoặc thậm chí 2), tiện ích mở rộng không còn cần thiết nữa vì containschức năng toàn cầu đã được tạo thành một cặp phương thức tiện ích mở rộng Array, cho phép bạn thực hiện một trong hai cách sau:

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

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

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

10
tìm là nhanh hơn.
Jim Balter

1
tùy thuộc vào những gì bạn đã từng sử dụng, các liên kết có thể cảm thấy trực quan và dễ nhớ hơn
Pirijan

4
Bạn có thể giải thích cú pháp của bạn bằng cách phá vỡ nó? Tôi chưa bao giờ thấy định dạng này trước đây và bạn đã có rất nhiều thứ nâng cao xảy ra cùng một lúc!
Kẻ xâm lược

40

Nếu bạn đang kiểm tra xem một thể hiện của một lớp hoặc cấu trúc tùy chỉnh có được chứa trong một mảng hay không, bạn sẽ cần triển khai giao thức Equitable trước khi bạn có thể sử dụng .contains (myObject).

Ví dụ:

struct Cup: Equatable {
    let filled:Bool
}

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

sau đó bạn có thể làm:

cupArray.contains(myCup)

Mẹo : Ghi đè == phải ở cấp toàn cầu, không nằm trong lớp / struct của bạn


32

Tôi đã sử dụng bộ lọc.

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

Nếu bạn muốn, bạn có thể nén nó để

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

Mong rằng sẽ giúp.


Cập nhật cho Swift 2

Thắng lợi cho việc triển khai mặc định!

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

Tôi thích giải pháp lọc vì bạn có thể sử dụng nó cho tất cả mọi thứ. Chẳng hạn, tôi đã chuyển một số mã được lặp và lặp để thử xem danh sách đã có một mục với một trong các trường có chứa giá trị chuỗi chưa. Đó là một dòng trong Swift, sử dụng bộ lọc trên trường đó.
Maury Markowitz

bộ lọc không hiệu quả vì nó luôn lặp trên tất cả các phần tử thay vì trả về ngay lập tức khi phần tử được tìm thấy. Sử dụng tốt hơn find () thay vào đó.
Thorsten

19

(Swift 3)

Kiểm tra xem một phần tử có tồn tại trong một mảng không (đáp ứng một số tiêu chí) và nếu có, hãy tiếp tục làm việc với phần tử đầu tiên như vậy

Nếu ý định là:

  1. Để kiểm tra xem một phần tử có tồn tại trong một mảng hay không (/ đáp ứng một số tiêu chí boolean, không nhất thiết phải kiểm tra tính bằng),
  2. Và nếu vậy, hãy tiếp tục và làm việc với phần tử đầu tiên như vậy,

Sau đó, một thay thế cho contains(_:)như blueprinted Sequencefirst(where:)của Sequence:

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

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

Trong ví dụ giả định này, việc sử dụng nó có vẻ ngớ ngẩn, nhưng sẽ rất hữu ích nếu truy vấn các mảng của các loại phần tử không cơ bản để tồn tại bất kỳ phần tử nào đáp ứng một số điều kiện. Ví dụ

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.

Bất kỳ hoạt động xích sử dụng .filter { ... some condition }.firstcó thể được thay thế bằng first(where:). Cái sau cho thấy ý định tốt hơn và có lợi thế về hiệu suất so với các thiết bị không lười biếng có thể .filter, vì những thứ này sẽ vượt qua toàn bộ mảng trước khi trích xuất phần tử đầu tiên (có thể) đi qua bộ lọc.


Kiểm tra xem một phần tử có tồn tại trong một mảng không (đáp ứng một số tiêu chí) và nếu có, hãy loại bỏ phần tử đầu tiên như vậy

Một bình luận bên dưới các truy vấn:

Làm thế nào tôi có thể loại bỏ firstSuchElementkhỏi mảng?

Một trường hợp sử dụng tương tự như trường hợp trên là loại bỏ phần tử đầu tiên đáp ứng một vị từ đã cho. Để làm như vậy, index(where:)phương thức Collection(có sẵn để thu thập mảng) có thể được sử dụng để tìm chỉ mục của phần tử đầu tiên đáp ứng vị từ, sau đó chỉ mục có thể được sử dụng với remove(at:)phương thức Array(có thể; nếu nó tồn tại) loại bỏ yếu tố đó

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

Hoặc, nếu bạn muốn xóa phần tử khỏi mảng và làm việc với , hãy áp dụng phương thức Optional: s map(_:)cho điều kiện (để .some(...)trả về từ index(where:)) sử dụng kết quả từ index(where:)để loại bỏ và bắt phần tử bị xóa khỏi mảng (trong mệnh đề ràng buộc tùy chọn) .

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
}

Lưu ý rằng trong ví dụ được nêu ở trên, các thành viên mảng là các loại giá trị đơn giản ( Stringví dụ), do đó, việc sử dụng một vị từ để tìm một thành viên nhất định là hơi quá, vì chúng ta có thể kiểm tra sự bằng nhau bằng cách sử dụng index(of:)phương pháp đơn giản hơn như trong câu trả lời của @ DogCoffee . Nếu áp dụng phương pháp tìm và loại bỏ ở trên choPersonTuy nhiên, ví dụ, sử dụng index(where:)với một vị từ là phù hợp (vì chúng ta không còn kiểm tra tính bằng mà để hoàn thành một vị từ được cung cấp).


Làm cách nào tôi có thể xóa FirstSuchEuity khỏi mảng?
i6x86

@ i6x86 cảm ơn câu hỏi. Tôi đã cập nhật câu trả lời của mình với một ví dụ về cách loại bỏ phần tử (và cả cách loại bỏ và nắm bắt phần tử đã xóa).
dfri

14

Cách đơn giản nhất để thực hiện điều này là sử dụng bộ lọc trên mảng.

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

resultsẽ có phần tử tìm thấy nếu nó tồn tại và sẽ trống nếu phần tử không tồn tại. Vì vậy, chỉ cần kiểm tra nếu resulttrống sẽ cho bạn biết liệu phần tử có tồn tại trong mảng hay không. Tôi sẽ sử dụng như sau:

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

giải pháp tuyệt vời. vì vậy phương thức này trả về một mảng. Tuy nhiên, tôi đang sử dụng điều này để tìm kiếm một "id". Trong ứng dụng của tôi d là duy nhất, vì vậy chỉ có một kết quả. Có cách nào để trả về chỉ 1 kết quả không? Tôi đang sử dụng kết quả [0] ngay bây giờ
Dan Beaulieu

3
@DanBeaulieu Làm một cái gì đó như let result = elements.filter { $0==5 }.firstsẽ hoàn thành những gì bạn đang tìm kiếm.
davetw12

7

Swift 4/5

Một cách khác để đạt được điều này là với chức năng lọc

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

6

Kể từ Swift 2.1 NSArrays có containsObjectthể được sử dụng như vậy:

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

4
Trên thực tế đó là cho một NSArray. Không phải là một mảng nhanh chóng
Tycho Pandelaar 15/03/2016

Vâng, nhưng bạn có thể tạm thời chuyển đổi mảng swift của mình thành NSArray: nếu để tempNSArrayForChecking = mySwiftArray làm NSArray? trong đó tempNSArrayForChecking.containsObject (objectImCheckingFor) {// myArray có đối tượng}
Vitalii

4

Chỉ trong trường hợp bất kỳ ai đang cố gắng tìm nếu một indexPathtrong số những người được chọn (như trong một UICollectionViewhoặc UITableView cellForItemAtIndexPathchức năng):

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

4

Mảng

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

Kiểm tra sự hiện diện của các yếu tố

elements.contains(5) // true

Lấy chỉ số các yếu tố

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

Lấy số phần tử

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

3

Đây là phần mở rộng nhỏ của tôi, tôi vừa viết để kiểm tra xem mảng đại biểu của tôi có chứa đối tượng ủy nhiệm hay không ( Swift 2 ). :) Nó cũng hoạt động với các loại giá trị như một nét duyên dáng.

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

Nếu bạn có một ý tưởng làm thế nào để tối ưu hóa mã này, hơn là chỉ cho tôi biết.


2

nếu người dùng tìm thấy các phần tử mảng cụ thể thì sử dụng mã bên dưới giống như giá trị nguyên.

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

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

2

Nhanh

Nếu bạn không sử dụng đối tượng thì bạn có thể sử dụng mã này để chứa.

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

if elements.contains(50) {

   print("true")

}

Nếu bạn đang sử dụng NSObject Class trong swift. Biến này là theo yêu cầu của tôi. bạn có thể sửa đổi cho yêu cầu của bạn.

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

Đây là cho một loại dữ liệu tương tự.

{ $0.user_id == cliectScreenSelectedObject.user_id }

Nếu bạn muốn loại AnyObject.

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

Tình trạng đầy đủ

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

    cliectScreenSelected.append(cliectScreenSelectedObject)

    print("Object Added")

} else {

    print("Object already exists")

 }

1

Còn việc sử dụng bảng băm cho công việc, như thế này thì sao?

đầu tiên, tạo một hàm chung "bản đồ băm", mở rộng giao thức Sequence.

extension Sequence where Element: Hashable {

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

Tiện ích mở rộng này sẽ hoạt động miễn là các mục trong mảng tuân thủ Hashable, như số nguyên hoặc chuỗi, đây là cách sử dụng ...

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

Nhưng bây giờ, hãy tập trung kiểm tra xem phần tử có trong mảng không.

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 +
Bạn có thể dễ dàng xác minh ví dụ của mình có phải là một mảng hay không bằng chức năng sau.

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

   return false
}

Thậm chí bạn có thể truy cập nó như sau. Bạn sẽ nhận được nilnếu đối tượng sẽ không phải là một mảng.

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

   return nil
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.