Bagaimana menemukan indeks item daftar di Swift?

442

Saya mencoba mencari item indexdengan mencari a list. Adakah yang tahu cara melakukannya?

Saya melihat ada list.StartIndexdan list.EndIndextapi saya ingin sesuatu seperti ular sanca list.index("text").

Chéyo
sumber

Jawaban:

822

Karena swift dalam beberapa hal lebih fungsional daripada berorientasi objek (dan Array adalah struct, bukan objek), gunakan fungsi "find" untuk beroperasi pada array, yang mengembalikan nilai opsional, jadi bersiaplah untuk menangani nilai nil:

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

Pembaruan untuk Swift 2.0:

Fungsi lama findtidak didukung lagi dengan Swift 2.0!

Dengan Swift 2.0, Arraymemperoleh kemampuan untuk menemukan indeks elemen menggunakan fungsi yang didefinisikan dalam ekstensi CollectionType(yang Arraymengimplementasikan):

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

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

Selain itu, menemukan elemen pertama dalam array yang memenuhi predikat didukung oleh ekstensi lain dari 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

Perhatikan bahwa kedua fungsi ini mengembalikan nilai opsional, seperti yang finddilakukan sebelumnya.

Pembaruan untuk Swift 3.0:

Perhatikan sintaks indexOf telah berubah. Untuk item yang sesuai dengan EquatableAnda dapat menggunakan:

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

Dokumentasi terperinci dari metode ini dapat ditemukan di https://developer.apple.com/reference/swift/array/1689674-index

Untuk item array yang tidak sesuai dengan EquatableAnda harus menggunakan index(where:):

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

Pembaruan untuk Swift 4.2:

Dengan Swift 4.2, indextidak lagi digunakan tetapi dipisahkan menjadi firstIndexdan lastIndexuntuk klarifikasi yang lebih baik. Jadi tergantung pada apakah Anda mencari indeks item pertama atau terakhir:

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

let indexOfA = arr.firstIndex(of: "a") // 0
let indexOfB = arr.lastIndex(of: "a") // 3
Sebastian Schuth
sumber
22
Di mana Anda belajar tentang fungsi temukan? Sepertinya saya tidak dapat menemukan dokumentasi "find" atau fungsi global lainnya
Johannes
14
Berasal dari dunia OOP, bagaimana saya bisa menemukan fungsi mengambang seperti ini?
Rudolf Adamkovič
4
Mereka tampaknya sebagian besar tidak berdokumen. Lihat praktisswift.com/2014/06/14/... untuk daftar (tetapi perlu diketahui bahwa saya tidak memeriksa apakah daftar sudah lengkap atau terbaru).
Sebastian Schuth
5
Johannes dan @Rudolf - gunakan Dash.app. Ini adalah aplikasi OS X untuk menelusuri dokumentasi. Ini memiliki referensi bahasa untuk Swift yang memiliki daftar semua fungsi mengambang gratis. Mudah difilter dan dicari. Tidak bisa hidup tanpanya.
Bjorn
4
FYI: Jika Anda menggunakan indexOfarray struct yang Anda tentukan sendiri, struct Anda harus mematuhi Equatableprotokol.
Matthew Quiros
202

tl; dr:

Untuk kelas, Anda mungkin mencari:

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

Jawaban lengkap:

Saya pikir perlu disebutkan bahwa dengan tipe referensi ( class) Anda mungkin ingin melakukan perbandingan identitas , dalam hal ini Anda hanya perlu menggunakan ===operator identitas dalam penutupan predikat:


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

Perhatikan bahwa sintaks di atas menggunakan sintaks trailing closure, dan setara dengan:

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


Swift 4 / Swift 3 - fungsi yang dulu disebut index

Swift 2 - fungsi yang dulu disebut indexOf

* Catat komentar yang relevan dan berguna oleh paulbailey tentang classjenis yang diterapkan Equatable, di mana Anda perlu mempertimbangkan apakah Anda harus membandingkan penggunaan ===( operator identitas ) atau ==( operator kesetaraan ). Jika Anda memutuskan untuk mencocokkan menggunakan ==, maka Anda cukup menggunakan metode yang disarankan oleh orang lain ( people.firstIndex(of: person1)).

Nikolay Suvandzhiev
sumber
6
Ini adalah posting yang berguna bagi mereka yang bertanya-tanya mengapa .indexOf (x) tidak berfungsi - solusi ini tidak terduga tetapi sangat jelas dalam retrospeksi.
Maury Markowitz
1
Terima kasih banyak untuk ini tetapi tidak jelas bagi saya sama sekali. Saya melihat dokumentasi dan saya benar-benar tidak mengerti mengapa saya perlu penutupan predikat ketika menggunakan indexOf pada tipe referensi? Rasanya seperti indexOf seharusnya sudah dapat menangani tipe referensi sendiri. Seharusnya tahu bahwa itu adalah tipe referensi dan bukan tipe nilai.
Chris
7
Jika Personmenerapkan Equatableprotokol, ini tidak diperlukan.
paulbailey
2
aku menerima: Binary operator '===' cannot be applied to operands of type '_' and 'Post', Postadalah struct saya ... ide?
David Seek
@ DavidSeek, structs(dan enums) adalah tipe nilai, bukan tipe referensi. Hanya tipe referensi (mis. class) Yang memiliki logika perbandingan identitas ( ===). Lihat jawaban lain untuk apa yang harus dilakukan structs(pada dasarnya Anda cukup menggunakan array.index(of: myStruct), pastikan jenis myStructkonformat ke Equatable( ==)).
Nikolay Suvandzhiev
81

Anda bisa filtermenggunakan array dengan penutup:

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

Dan Anda dapat menghitung array:

filtered.count // <= returns 1

Jadi, Anda dapat menentukan apakah array menyertakan elemen Anda dengan menggabungkan ini:

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

Jika Anda ingin menemukan posisi itu, saya tidak melihat cara yang mewah, tetapi Anda pasti bisa melakukannya seperti ini:

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

EDIT

Sementara kita melakukannya, untuk latihan yang menyenangkan, mari kita lanjutkan Arrayuntuk memiliki findmetode:

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

Sekarang kita bisa melakukan ini:

myList.find { $0 == 3 }
// returns the index position of 3 or nil if not found
gwcoffey
sumber
Untuk funsies saya menambahkan contoh lain di mana saya memperluas builtin Arrayuntuk memiliki findmetode yang melakukan apa yang Anda inginkan. Saya belum tahu apakah ini praktik yang baik, tetapi ini adalah eksperimen yang rapi.
gwcoffey
2
Hanya ingin menunjukkan, bahwa Anda harus menggunakan ++ idx sesuai dokumen: "Kecuali jika Anda memerlukan perilaku spesifik dari i ++, disarankan agar Anda menggunakan ++ i dan --i dalam semua kasus, karena mereka memiliki tipikal yang diharapkan perilaku memodifikasi saya dan mengembalikan hasilnya. "
Logan
Panggilan yang bagus. Ketika Anda memposting ini saya merevisinya untuk digunakan enumeratesehingga tidak berlaku lagi, tetapi Anda benar.
gwcoffey
Ya, saya ingat memperhatikannya dalam salah satu contoh ketika saya sedang melaluinya. Mencoba menempatkan diriku dalam kebiasaan sekarang :)
Logan
4
Agar ini bekerja di bawah Swift 2 / XCode 7 Anda perlu memodifikasinya sebagai berikut. Ganti (IncludedElement: T -> Bool) dengan (IncludedElement: Element -> Bool) dan ubah enumerate (self) menjadi self.enumerate
Scooter
35

Cepat 5

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

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

Contoh 1

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

Contoh2

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

Meskipun indexOf()bekerja dengan sempurna, itu hanya mengembalikan satu indeks.

Saya mencari cara yang elegan untuk mendapatkan berbagai indeks untuk elemen yang memenuhi beberapa syarat.

Inilah cara melakukannya:

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)
Serhii Yakovenko
sumber
12

Untuk kelas khusus, Anda perlu menerapkan protokol Setara.

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)
ZYiOS
sumber
9

Pembaruan untuk Swift 2:

sequence.contains (elemen) : Mengembalikan nilai true jika urutan yang diberikan (seperti array) berisi elemen yang ditentukan.

Cepat 1:

Jika Anda mencari hanya untuk memeriksa apakah suatu elemen terkandung di dalam array, yaitu, dapatkan indikator boolean, gunakan contains(sequence, element)alih-alih find(array, element):

berisi (urutan, elemen) : Mengembalikan nilai true jika urutan yang diberikan (seperti array) berisi elemen yang ditentukan.

Lihat contoh di bawah ini:

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.   
}
Zorayr
sumber
7

dalam Swift 4.2

.index (di mana :) diubah menjadi .firstIndex (di mana :)

array.firstIndex(where: {$0 == "person1"})
Ridho Octanio
sumber
6

Swift 4. Jika array Anda mengandung elemen tipe [String: AnyObject]. Jadi untuk menemukan indeks elemen gunakan kode di bawah ini

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)

Atau Jika Anda ingin menemukan indeks berdasarkan kunci dari Kamus. Di sini array berisi Objects of Model class dan saya mencocokkan properti 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
Gurjinder Singh
sumber
4

Cepat 2.1

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

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

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

Cepat 3

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

if let index = array.index(of: "1") {
    array.remove(at: index)
}
array.remove(at: 1)
Luca Davanzo
sumber
3
Anda bermutasi let array? Penggunaan selfdipertanyakan juga.
Chéyo
4

Di Swift 4 , jika Anda melintasi array DataModel Anda, pastikan model data Anda sesuai dengan Protokol yang Dapat Diterapkan, mengimplementasikan metode lhs = rhs, dan hanya dengan demikian Anda dapat menggunakan ".index (of". Misalnya

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

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

Lalu,

let index = self.photos.index(of: aPhoto)
Naishta
sumber
4

Dalam Swift 2 (dengan Xcode 7), Arraysertakan indexOfmetode yang disediakan oleh CollectionTypeprotokol. (Sebenarnya, dua indexOfmetode — satu yang menggunakan persamaan untuk mencocokkan suatu argumen, dan yang lainnya menggunakan penutupan).

Sebelum Swift 2, tidak ada cara untuk jenis generik seperti koleksi untuk menyediakan metode untuk jenis beton yang berasal dari mereka (seperti array). Jadi, di Swift 1.x, "indeks" adalah fungsi global ... Dan namanya juga diganti, jadi di Swift 1.x, fungsi global itu disebut find.

Mungkin juga (tetapi tidak perlu) menggunakan indexOfObjectmetode ini dari NSArray... atau metode pencarian lain yang lebih canggih dari Foundation yang tidak memiliki padanan dalam pustaka standar Swift. Hanya import Foundation(atau modul lain yang mengimpor Yayasan secara transitif), sampaikan Arrayke NSArray, dan Anda dapat menggunakan banyak metode pencarian NSArray.

rickster
sumber
4

Salah satu solusi ini bekerja untuk saya

Ini solusi yang saya miliki untuk 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
        })
Kevin ABRIOUX
sumber
2

Anda juga dapat menggunakan dolar perpustakaan fungsional untuk melakukan indexOf pada array seperti http://www.dollarswift.org/#indexof-indexof

$.indexOf([1, 2, 3, 1, 2, 3], value: 2) 
=> 1
Encore PTL
sumber
2

Jika Anda masih bekerja di Swift 1.x

lalu coba,

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

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

Untuk SWIFT 3 Anda dapat menggunakan fungsi sederhana

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

Ini akan memberikan posisi angka, sehingga Anda dapat menggunakan suka

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

Semoga bermanfaat

Marco
sumber
1

SWIFT 4

Katakanlah Anda ingin menyimpan nomor dari array bernama cardButtons ke cardNumber, Anda dapat melakukannya dengan cara ini:

let cardNumber = cardButtons.index(of: sender)

pengirim adalah nama tombol Anda


sumber
0

Cepat 4

Untuk jenis referensi:

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
    }
}
Menno
sumber
0

Di Swift 4/5, gunakan "firstIndex" untuk menemukan indeks.

let index = array.firstIndex{$0 == value}
Krunal Patel
sumber
0

Jika seseorang memiliki masalah ini

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

hanya lakukan ini

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

kemudian

guard let finalIndex = index?.toInt else {
    return false
}
Ahmed Safadi
sumber
0

Untuk (>= swift 4.0)

Ini agak sangat sederhana. Pertimbangkan Arrayobjek berikut .

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

Untuk mendapatkan indeks elemen rose, yang harus Anda lakukan adalah:

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

catatan:

  • Array.index(of:)mengembalikan sebuah Optional<Int>.

  • nil menyiratkan bahwa elemen tidak ada dalam array.

  • Anda mungkin ingin membuka paksa nilai yang dikembalikan atau menggunakan if-letuntuk menyiasati opsional.

Mohammed Sadiq
sumber
0

Cukup gunakan metode firstIndex.

array.firstIndex(where: { $0 == searchedItem })
erdikanik
sumber