如何在Swift中找到列表项的索引?


442

我正在尝试item index通过搜索找到一个list。有人知道该怎么做吗?

我看到了list.StartIndexlist.EndIndex但是我想要类似python的东西list.index("text")

Answers:


822

由于Swift在某些方面比面向对象的功能更强大(并且Array是结构,而不是对象),因此请使用函数“ find”对数组进行操作,该数组将返回可选值,因此请准备处理nil值:

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

Swift 2.0更新:

findSwift 2.0不再支持旧功能!

使用Swift 2.0,Array可以使用扩展CollectionType(定义为)中定义的函数来查找元素的索引Array

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

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

此外,另一个扩展支持在数组中找到满足谓词的第一个元素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

请注意,这两个函数像find以前一样返回可选值。

Swift 3.0更新:

注意indexOf的语法已更改。对于符合条件的物品,Equatable可以使用:

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

有关该方法的详细文档,请参见https://developer.apple.com/reference/swift/array/1689674-index

对于不符合条件的数组项,Equatable您需要使用index(where:)

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

Swift 4.2更新:

在Swift 4.2中,index不再使用它,而是将其分开firstIndexlastIndex进行更好的说明。因此,根据您要查找的项目的第一个还是最后一个索引:

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

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

21
您从哪里了解查找功能的?我似乎找不到“ find”或任何其他全局函数的任何文档
Johannes

14
来自OOP世界,我应该如何找到这种自由浮动函数?
RudolfAdamkovič2014年

4
他们似乎基本上没有证件。有关列表,请参见Practicalswift.com/2014/06/14/…(但请注意,我没有检查列表是否完整或最新)。
塞巴斯蒂安·舒斯

5
Johannes和@Rudolf-使用Dash.app。这是一个用于浏览文档的OS X应用程序。它具有Swift的语言参考,其中列出了所有自由浮动函数。易于过滤和搜索。没有它就无法生存。
比约恩

4
仅供参考:如果您要indexOf在自己定义的结构数组上使用,则结构必须符合Equatable协议。
马修·基罗斯

202

tl; dr:

对于课程,您可能正在寻找:

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

完整答案:

我认为值得一提的是,class您可能需要使用引用类型()进行身份比较,在这种情况下,您只需要===在谓词闭包中使用身份运算符即可:


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

请注意,以上语法使用结尾闭包语法,并且等效于:

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


Swift 4 / Swift 3-以前被调用的函数 index

Swift 2-以前被调用的函数 indexOf

*注意相关的和有用的评论通过paulbailey有关class实现类型Equatable,你需要考虑你是否应该用比较===标识符)或==等式操作符)。如果决定使用进行匹配==,则可以简单地使用其他人(people.firstIndex(of: person1))建议的方法。


6
对于那些想知道为什么.indexOf(x)不起作用的人来说,这是一个有用的帖子-此解决方案是出乎意料的,但回想起来很明显。
莫里·马克维兹

1
非常感谢,但这一点对我来说并不明显。我查看了文档,但我真的不明白为什么在引用类型上使用indexOf时为什么需要断言?感觉indexOf应该已经能够自己处理引用类型。应该知道这是引用类型,而不是值类型。
克里斯

7
如果Person实施该Equatable协议,则不需要。
paulbailey's

2
我收到:Binary operator '===' cannot be applied to operands of type '_' and 'Post'Post我的结构...有什么主意吗?
David Seek

@DavidSeek structs(和enums)是值类型,而不是引用类型。仅引用类型(例如class)具有身份比较逻辑(===)。查看其他答案以解决问题structs(基本上,您只需使用array.index(of: myStruct),确保myStruct符合Equatable==)的类型)。
Nikolay Suvandzhiev

81

您可以filter使用闭包数组:

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

您可以计算一个数组:

filtered.count // <= returns 1

因此可以判断,如果阵列包括通过组合这些你的元素:

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

如果您想找到职位,我看不到花哨的方法,但是您当然可以这样:

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

编辑

在进行此操作的同时,让我们进行一下有趣的练习Array以扩展一种find方法:

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

现在我们可以这样做:

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

为了好玩,我添加了另一个示例,其中我扩展了内置函数,Array使其具有可以执行所需功能的find方法。我还不知道这是否是一个好习惯,但这是一个很好的实验。
gwcoffey 2014年

2
只是要指出,您应该按照docs使用++ idx:“除非您需要i ++的特定行为,否则建议在所有情况下都使用++ i和--i,因为它们具有典型的预期效果。修改i并返回结果的行为。”
Logan 2014年

好决定。在您发布此内容时,我正在对其进行修改,以enumerate使其不再适用,但是您绝对正确。
gwcoffey 2014年

是的,我记得在进行示例操作时注意到其中一个例子。现在想让自己养成习惯:)
Logan 2014年

4
为了在Swift 2 / XCode 7下工作,您需要进行如下修改。将(includedElement:T-> Bool)替换为(includedElement:Element-> Bool)并将enumerate(self)更改为self.enumerate
滑板车

35

迅捷5

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

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

例1

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

例2

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

25

虽然indexOf()效果很好,但它只返回一个索引。

我一直在寻找一种优雅的方法来获取满足某些条件的元素的索引数组。

这是可以做到的:

斯威夫特3:

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

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

print(indexes)

斯威夫特2:

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

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

print(indexes)

12

对于自定义类,您需要实现Equatable协议。

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

Swift 2更新:

sequence.contains(element):如果给定序列(例如数组)包含指定的元素,则返回true。

斯威夫特1:

如果您只是在检查数组中是否包含元素,即仅获取布尔值指示符,请使用contains(sequence, element)代替find(array, element)

contains(sequence,element):如果给定序列(例如数组)包含指定的元素,则返回true。

请参见下面的示例:

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


6

Swift4。如果您的数组包含[String:AnyObject]类型的元素。所以要找到元素的索引使用下面的代码

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)

或者如果您想根据字典中的关键字找到索引。这里数组包含Model类的对象,并且我正在匹配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

斯威夫特2.1

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

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

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

迅捷3

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

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

3
你正在变异let array吗?的使用self也值得怀疑。
Chéyo

4

Swift 4中,如果要遍历DataModel数组,请确保您的数据模型符合Equatable Protocol,实现lhs = rhs方法,然后才可以使用“ .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
    }
}

然后,

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

4

在Swift 2(带有Xcode 7)中,Array包括indexOfCollectionType协议提供的方法。(实际上,有两种indexOf方法-一种使用相等性来匹配参数,另一种使用闭包。)

在Swift 2之前,还没有一种方法可以让通用类型(如集合)提供从其派生的具体类型(如数组)的方法。因此,在Swift 1.x中,“ index of”是一个全局函数...并且它也被重命名,因此在Swift 1.x中,该全局函数被称为find

也可以(但不是必须)使用...中的indexOfObject方法,NSArray或者使用Foundation中其他任何更复杂的搜索方法,这些方法在Swift标准库中都没有等效项。只需将它import Foundation(或可过渡导入Foundation的另一个模块)转换ArrayNSArray,即可在上使用多种搜索方法NSArray


4

任何一种解决方案都对我有用

这是我对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

如果您仍在使用Swift 1.x

然后尝试

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

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

1

对于SWIFT 3,您可以使用简单的功能

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

这将给出数字位置,因此您可以使用

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

希望有用


1

SWIFT 4

假设您要将一个名为cardButtons的数组中的数字存储到cardNumber中,可以这样进行:

let cardNumber = cardButtons.index(of: sender)

发件人是您按钮的名称


0

斯威夫特4

对于参考类型:

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

万一有人有这个问题

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

jsut做到这一点

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

然后

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

0

对于 (>= swift 4.0)

这非常简单。考虑以下Array对象。

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

为了获得element的索引rose,您要做的就是:

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

注意:

  • Array.index(of:)返回Optional<Int>

  • nil 表示该元素不在数组中。

  • 您可能需要强制拆开返回的值或使用if-let来绕过可选值。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.