Làm cách nào để tìm chỉ mục của danh sách mục trong Swift?


442

Tôi đang cố gắng tìm một item indexbằng cách tìm kiếm a list. Có ai biết làm thế nào để làm điều đó?

Tôi thấy có list.StartIndexlist.EndIndexnhưng tôi muốn một cái gì đó giống như của trăn list.index("text").

Câu trả lời:


822

Vì swift ở một số khía cạnh có nhiều chức năng hơn hướng đối tượng (và Mảng là cấu trúc, không phải đối tượng), sử dụng hàm "find" để hoạt động trên mảng, trả về giá trị tùy chọn, vì vậy hãy chuẩn bị để xử lý giá trị nil:

let arr:Array = ["a","b","c"]
find(arr, "c")!              // 2
find(arr, "d")               // nil

Cập nhật cho Swift 2.0:

findChức năng cũ không được hỗ trợ nữa với Swift 2.0!

Với Swift 2.0, Arrayđạt được khả năng tìm chỉ mục của một phần tử bằng cách sử dụng hàm được xác định trong phần mở rộng của CollectionType( Arraythực hiện):

let arr = ["a","b","c"]

let indexOfA = arr.indexOf("a") // 0
let indexOfB = arr.indexOf("b") // 1
let indexOfD = arr.indexOf("d") // nil

Ngoài ra, việc tìm phần tử đầu tiên trong một mảng đáp ứng một vị từ được hỗ trợ bởi một phần mở rộng khác của CollectionType:

let arr2 = [1,2,3,4,5,6,7,8,9,10]
let indexOfFirstGreaterThanFive = arr2.indexOf({$0 > 5}) // 5
let indexOfFirstGreaterThanOneHundred = arr2.indexOf({$0 > 100}) // nil

Lưu ý rằng hai hàm này trả về các giá trị tùy chọn, như findđã làm trước đó.

Cập nhật cho Swift 3.0:

Lưu ý cú pháp của indexOf đã thay đổi. Đối với các mặt hàng phù hợp với Equatablebạn có thể sử dụng:

let indexOfA = arr.index(of: "a")

Một tài liệu chi tiết về phương pháp có thể được tìm thấy tại https://developer.apple.com/reference/swift/array/1689674-index

Đối với các mục mảng không phù hợp với Equatablebạn sẽ cần sử dụng index(where:):

let index = cells.index(where: { (item) -> Bool in
  item.foo == 42 // test if this is the item you're looking for
})

Cập nhật cho Swift 4.2:

Với Swift 4.2, indexkhông còn được sử dụng mà được tách ra firstIndexlastIndexđể làm rõ hơn. Vì vậy, tùy thuộc vào việc bạn đang tìm kiếm chỉ mục đầu tiên hoặc cuối cùng của mặt hàng:

let arr = ["a","b","c","a"]

let indexOfA = arr.firstIndex(of: "a") // 0
let indexOfB = arr.lastIndex(of: "a") // 3

22
Bạn đã tìm hiểu về chức năng tìm ở đâu? Tôi dường như không thể tìm thấy bất kỳ tài liệu nào về "tìm" hoặc bất kỳ chức năng toàn cầu nào khác
Julian

14
Đến từ thế giới OOP, làm thế nào tôi có thể tìm thấy loại chức năng nổi miễn phí này?
Rudolf Adamkovič

4
Họ dường như phần lớn không có giấy tờ. Xem Realisticswift.com/2014/06/14/ Khăn để biết danh sách (nhưng lưu ý rằng tôi đã không kiểm tra xem danh sách này đã hoàn thành hay chưa cập nhật).
Sebastian Schuth

5
Julian và @Rudolf - sử dụng Dash.app. Đây là một ứng dụng OS X để duyệt tài liệu. Nó có một tham chiếu ngôn ngữ cho Swift có một danh sách tất cả các hàm nổi miễn phí. Dễ dàng lọc và tìm kiếm. Không thể sống mà không có nó.
Bjorn

4
FYI: Nếu bạn đang sử dụng indexOftrên một loạt các cấu trúc mà bạn tự xác định, cấu trúc của bạn phải tuân thủ Equatablegiao thức.
Matthew Quiros

202

tl; dr:

Đối với các lớp học, bạn có thể đang tìm kiếm:

let index = someArray.firstIndex{$0 === someObject}

Câu trả lời đầy đủ:

Tôi nghĩ rằng đáng để đề cập rằng với các loại tham chiếu ( class) bạn có thể muốn thực hiện so sánh danh tính , trong trường hợp đó bạn chỉ cần sử dụng ===toán tử nhận dạng trong bao đóng vị ngữ:


Swift 5, Swift 4.2:

let person1 = Person(name: "John")
let person2 = Person(name: "Sue")
let person3 = Person(name: "Maria")
let person4 = Person(name: "Loner")

let people = [person1, person2, person3]

let indexOfPerson1 = people.firstIndex{$0 === person1} // 0
let indexOfPerson2 = people.firstIndex{$0 === person2} // 1
let indexOfPerson3 = people.firstIndex{$0 === person3} // 2
let indexOfPerson4 = people.firstIndex{$0 === person4} // nil

Lưu ý rằng cú pháp trên sử dụng cú pháp đóng dấu theo dõi và tương đương với:

let indexOfPerson1 = people.firstIndex(where: {$0 === person1})


Swift 4 / Swift 3 - chức năng được gọi là index

Swift 2 - chức năng được gọi là indexOf

* Lưu ý nhận xét có liên quan và hữu ích của paulbailey về classcác loại triển khai Equatable, nơi bạn cần xem xét liệu bạn nên so sánh bằng cách sử dụng ===( toán tử nhận dạng ) hay ==( toán tử đẳng thức ). Nếu bạn quyết định khớp bằng cách sử dụng ==, thì bạn chỉ cần sử dụng phương thức được đề xuất bởi người khác ( people.firstIndex(of: person1)).


6
Đây là một bài viết hữu ích cho những người thắc mắc tại sao .indexOf (x) không hoạt động - giải pháp này bất ngờ nhưng hoàn toàn rõ ràng khi nhìn lại.
Maury Markowitz

1
Cảm ơn rất nhiều vì điều này nhưng nó không rõ ràng đối với tôi. Tôi đã xem tài liệu và tôi thực sự không hiểu tại sao tôi lại cần đóng vị ngữ khi sử dụng indexOf trên một kiểu tham chiếu? Có vẻ như indexOf đã có thể tự xử lý các loại tham chiếu. Cần biết rằng đó là loại tham chiếu chứ không phải loại giá trị.
Chris

7
Nếu Personthực hiện Equatablegiao thức, điều này sẽ không cần thiết.
paulbailey

2
Tôi đang nhận được : Binary operator '===' cannot be applied to operands of type '_' and 'Post', Postcấu trúc của tôi ... có ý kiến ​​gì không?
David Seek

@DavidSeek, structs(và enums) là các loại giá trị, không phải loại tham chiếu. Chỉ các loại tham chiếu (ví dụ class) có logic so sánh nhận dạng ( ===). Kiểm tra các câu trả lời khác để biết phải làm gì structs(về cơ bản bạn chỉ cần sử dụng array.index(of: myStruct), đảm bảo loại myStructtuân thủ Equatable( ==)).
Nikolay Suvandzhiev

81

Bạn có thể filtermột mảng với một bao đóng:

var myList = [1, 2, 3, 4]
var filtered = myList.filter { $0 == 3 }  // <= returns [3]

Và bạn có thể đếm một mảng:

filtered.count // <= returns 1

Vì vậy, bạn có thể xác định xem một mảng có bao gồm phần tử của bạn hay không bằng cách kết hợp các phần sau:

myList.filter { $0 == 3 }.count > 0  // <= returns true if the array includes 3

Nếu bạn muốn tìm vị trí, tôi không thấy cách ưa thích, nhưng bạn chắc chắn có thể làm điều đó như thế này:

var found: Int?  // <= will hold the index if it was found, or else will be nil
for i in (0..x.count) {
    if x[i] == 3 {
        found = i
    }
}

BIÊN TẬP

Trong khi chúng ta đang ở đó, để có một bài tập thú vị, hãy mở rộng Arrayđể có một findphương pháp:

extension Array {
    func find(includedElement: T -> Bool) -> Int? {
        for (idx, element) in enumerate(self) {
            if includedElement(element) {
                return idx
            }
        }
        return nil
    }
}

Bây giờ chúng ta có thể làm điều này:

myList.find { $0 == 3 }
// returns the index position of 3 or nil if not found

Đối với các cuộc vui, tôi đã thêm một ví dụ khác trong đó tôi mở rộng nội dung Arrayđể có một findphương thức thực hiện những gì bạn muốn. Tôi chưa biết nếu đây là một thực hành tốt, nhưng nó là một thử nghiệm gọn gàng.
gwcoffey

2
Chỉ muốn chỉ ra rằng, bạn nên sử dụng ++ idx theo tài liệu: "Trừ khi bạn cần hành vi cụ thể của i ++, bạn nên sử dụng ++ i và --i trong mọi trường hợp, vì chúng có dự kiến ​​điển hình hành vi sửa đổi tôi và trả lại kết quả. "
Logan

Cuộc gọi tốt Khi bạn đăng bài này, tôi đã sửa đổi nó để sử dụng enumerateđể nó không còn áp dụng nữa, nhưng bạn hoàn toàn đúng.
gwcoffey

Phải, tôi nhớ đã nhận thấy nó trong một trong những ví dụ khi tôi trải qua. Cố gắng tập cho mình thói quen ngay bây giờ :)
Logan

4
Để điều này hoạt động theo Swift 2 / XCode 7, bạn cần sửa đổi nó như sau. Thay thế (bao gồm cả phần bổ sung: T -> Bool) bằng (bao gồm phần bổ sung: Phần tử -> Bool) và thay đổi liệt kê (bản thân) thành self.enum Cả
tay ga

35

Swift 5

func firstIndex(of element: Element) -> Int?

var alphabets = ["A", "B", "E", "D"]

Ví dụ 1

let index = alphabets.firstIndex(where: {$0 == "A"})

Ví dụ2

if let i = alphabets.firstIndex(of: "E") {
    alphabets[i] = "C" // i is the index
}
print(alphabets)
// Prints "["A", "B", "C", "D"]"

25

Trong khi indexOf()hoạt động hoàn hảo, nó chỉ trả về một chỉ mục.

Tôi đang tìm kiếm một cách thanh lịch để có được một loạt các chỉ mục cho các yếu tố thỏa mãn một số điều kiện.

Đây là cách nó có thể được thực hiện:

Swift 3:

let array = ["apple", "dog", "log"]

let indexes = array.enumerated().filter {
    $0.element.contains("og")
    }.map{$0.offset}

print(indexes)

Swift 2:

let array = ["apple", "dog", "log"]

let indexes = array.enumerate().filter {
    $0.element.containsString("og")
    }.map{$0.index}

print(indexes)

12

Đối với lớp tùy chỉnh, bạn cần thực hiện giao thức Equitable.

import Foundation

func ==(l: MyClass, r: MyClass) -> Bool {
  return l.id == r.id
}

class MyClass: Equtable {
    init(id: String) {
        self.msgID = id
    }

    let msgID: String
}

let item = MyClass(3)
let itemList = [MyClass(1), MyClass(2), item]
let idx = itemList.indexOf(item)

printl(idx)

9

Cập nhật cho Swift 2:

Sequ.contains (phần tử) : Trả về true nếu một chuỗi đã cho (chẳng hạn như một mảng) có chứa phần tử đã chỉ định.

Swift 1:

Nếu bạn đang tìm kiếm chỉ để kiểm tra xem một phần tử có được chứa trong một mảng hay không, nghĩa là, chỉ cần lấy một chỉ báo boolean, sử dụng contains(sequence, element)thay vì find(array, element):

chứa (chuỗi, phần tử) : Trả về true nếu một chuỗi đã cho (chẳng hạn như một mảng) chứa phần tử đã chỉ định.

Xem ví dụ dưới đây:

var languages = ["Swift", "Objective-C"]
contains(languages, "Swift") == true
contains(languages, "Java") == false
contains([29, 85, 42, 96, 75], 42) == true
if (contains(languages, "Swift")) {
  // Use contains in these cases, instead of find.   
}

7

trong Swift 4.2

.index (nơi :) đã được đổi thành .first Index (nơi :)

array.firstIndex(where: {$0 == "person1"})

6

Swift 4. Nếu mảng của bạn chứa các phần tử thuộc loại [String: AnyObject]. Vì vậy, để tìm chỉ mục của phần tử sử dụng mã dưới đây

var array = [[String: AnyObject]]()// Save your data in array
let objectAtZero = array[0] // get first object
let index = (self.array as NSArray).index(of: objectAtZero)

Hoặc Nếu bạn muốn tìm chỉ mục trên cơ sở khóa từ điển. Ở đây mảng chứa các đối tượng của lớp Model và tôi khớp với thuộc tính id.

   let userId = 20
    if let index = array.index(where: { (dict) -> Bool in
           return dict.id == userId // Will found index of matched id
    }) {
    print("Index found")
    }
OR
      let storeId = Int(surveyCurrent.store_id) // Accessing model key value
      indexArrUpTo = self.arrEarnUpTo.index { Int($0.store_id) == storeId }! // Array contains models and finding specific one

4

Swift 2.1

var array = ["0","1","2","3"]

if let index = array.indexOf("1") {
   array.removeAtIndex(index)
}

print(array) // ["0","2","3"]

Swift 3

var array = ["0","1","2","3"]

if let index = array.index(of: "1") {
    array.remove(at: index)
}
array.remove(at: 1)

3
bạn đang đột biến a let array? Việc sử dụng selflà nghi vấn cũng có.
Chéyo

4

Trong Swift 4 , nếu bạn đang duyệt qua mảng DataModel của mình, hãy đảm bảo mô hình dữ liệu của bạn tuân thủ Giao thức tương đương, triển khai phương thức lhs = rhs và chỉ sau đó bạn mới có thể sử dụng ".index (of".

class Photo : Equatable{
    var imageURL: URL?
    init(imageURL: URL){
        self.imageURL = imageURL
    }

    static func == (lhs: Photo, rhs: Photo) -> Bool{
        return lhs.imageURL == rhs.imageURL
    }
}

Và sau đó,

let index = self.photos.index(of: aPhoto)

4

Trong Swift 2 (với Xcode 7), Arraybao gồm một indexOfphương thức được cung cấp bởi CollectionTypegiao thức. (Trên thực tế, hai indexOfphương thức mà một phương thức sử dụng đẳng thức để khớp với một đối số và một phương thức khác sử dụng một bao đóng.)

Trước Swift 2, không có cách nào cho các loại chung chung như bộ sưu tập cung cấp phương thức cho các loại cụ thể có nguồn gốc từ chúng (như mảng). Vì vậy, trong Swift 1.x, "index of" là một hàm toàn cục ... Và nó cũng được đổi tên, vì vậy, trong Swift 1.x, hàm toàn cầu đó được gọi làfind .

Cũng có thể (nhưng không cần thiết) sử dụng indexOfObjectphương pháp từ NSArray... hoặc bất kỳ phương pháp tìm kiếm meth phức tạp nào khác từ Tổ chức không có tương đương trong thư viện chuẩn Swift. Chỉ import Foundation(hoặc một mô-đun khác nhập quá mức Foundation), Arraychuyển sang NSArrayvà bạn có thể sử dụng nhiều phương pháp tìm kiếm trên NSArray.


4

Bất kỳ giải pháp này làm việc cho tôi

Đây là giải pháp tôi có cho Swift 4:

let monday = Day(name: "M")
let tuesday = Day(name: "T")
let friday = Day(name: "F")

let days = [monday, tuesday, friday]

let index = days.index(where: { 
            //important to test with === to be sure it's the same object reference
            $0 === tuesday
        })


2

Nếu bạn vẫn đang làm việc trong Swift 1.x

vậy hãy thử đi,

let testArray = ["A","B","C"]

let indexOfA = find(testArray, "A") 
let indexOfB = find(testArray, "B")
let indexOfC = find(testArray, "C")

1

Đối với SWIFT 3, bạn có thể sử dụng một chức năng đơn giản

func find(objecToFind: String?) -> Int? {
   for i in 0...arrayName.count {
      if arrayName[i] == objectToFind {
         return i
      }
   }
return nil
}

Điều này sẽ cho vị trí số, vì vậy bạn có thể sử dụng như

arrayName.remove(at: (find(objecToFind))!)

Hy vọng sẽ hữu ích


1

Chuyển 4

Giả sử bạn muốn lưu trữ một số từ mảng được gọi là cardButtons vào cardNumber, bạn có thể thực hiện theo cách này:

let cardNumber = cardButtons.index(of: sender)

người gửi là tên của nút của bạn


0

Swift 4

Đối với các loại tài liệu tham khảo:

extension Array where Array.Element: AnyObject {

    func index(ofElement element: Element) -> Int? {
        for (currentIndex, currentElement) in self.enumerated() {
            if currentElement === element {
                return currentIndex
            }
        }
        return nil
    }
}

0

Trong Swift 4/5, sử dụng "First Index" để tìm chỉ mục.

let index = array.firstIndex{$0 == value}

0

Trong trường hợp ai đó có vấn đề này

Cannot invoke initializer for type 'Int' with an argument list of type '(Array<Element>.Index?)'

jsut làm điều này

extension Int {
    var toInt: Int {
        return self
    }
}

sau đó

guard let finalIndex = index?.toInt else {
    return false
}

0

Dành cho (>= swift 4.0)

Nó khá đơn giản. Hãy xem xét các Arrayđối tượng sau đây .

var names: [String] = ["jack", "rose", "jill"]

Để có được chỉ mục của phần tử rose, tất cả những gì bạn phải làm là:

names.index(of: "rose") // returns 1

Ghi chú:

  • Array.index(of:)trả về một Optional<Int>.

  • nil ngụ ý rằng phần tử không có trong mảng.

  • Bạn có thể muốn hủy bỏ giá trị được trả về hoặc sử dụng giá trị if-letxung quanh tùy chọn.


0

Chỉ cần sử dụng phương pháp First Index.

array.firstIndex(where: { $0 == searchedItem })
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.