【问题标题】:Find an object in array?在数组中找到一个对象?
【发布时间】:2015-04-27 23:13:37
【问题描述】:

Swift 在 Underscore.js 中有类似 _.findWhere 的东西吗?

我有一个 T 类型的结构数组,并想检查数组是否包含一个结构对象,其 name 属性等于 Foo

尝试使用 find()filter() 但它们仅适用于原始类型,例如StringInt。抛出关于不符合Equitable 协议或类似内容的错误。

【问题讨论】:

  • 这可能是您正在寻找的:Find Object with Property in Array.
  • 为什么不转换成 nsdictionary 并搜索
  • 我相信 find 在 Swift 2.0 中不再可用。我将一些 1.2 代码转换为 Swift 2.0,它说要改用 IndexOf。

标签: ios swift


【解决方案1】:

SWIFT 5

检查元素是否存在

if array.contains(where: {$0.name == "foo"}) {
   // it exists, do something
} else {
   //item could not be found
}

获取元素

if let foo = array.first(where: {$0.name == "foo"}) {
   // do something with foo
} else {
   // item could not be found
}

获取元素及其偏移量

if let foo = array.enumerated().first(where: {$0.element.name == "foo"}) {
   // do something with foo.offset and foo.element
} else {
   // item could not be found
}

获取偏移量

if let fooOffset = array.firstIndex(where: {$0.name == "foo"}) {
    // do something with fooOffset
} else {
    // item could not be found
}

【讨论】:

  • 不错的 Swift 风格的答案!
  • 谢谢你是我的保护者,这已经清理了我的代码很多
  • 如何检查多个条件说我需要检查数组 $0.name == "foo" 是否执行一项操作,$0.name == "boo" 是否执行另一项操作
  • 这对我的帮助超过了 2020 年公认的答案。
  • 如何检查 $0.name 是否包含字符串“foo”?谁能给出那个语法
【解决方案2】:

您可以将Array 上可用的index 方法与谓词(see Apple's documentation here) 结合使用。

func index(where predicate: (Element) throws -> Bool) rethrows -> Int?

对于您的具体示例,这将是:

Swift 5.0

if let i = array.firstIndex(where: { $0.name == "Foo" }) {
    return array[i]
}

Swift 3.0

if let i = array.index(where: { $0.name == Foo }) {
    return array[i]
}

Swift 2.0

if let i = array.indexOf({ $0.name == Foo }) {
    return array[i]
}

【讨论】:

【解决方案3】:

FWIW,如果你不想使用自定义函数或扩展,你可以:

let array = [ .... ]
if let found = find(array.map({ $0.name }), "Foo") {
    let obj = array[found]
}

这将首先生成name 数组,然后从中生成find

如果你有巨大的数组,你可能想这样做:

if let found = find(lazy(array).map({ $0.name }), "Foo") {
    let obj = array[found]
}

或者也许:

if let found = find(lazy(array).map({ $0.name == "Foo" }), true) {
    let obj = array[found]
}

【讨论】:

  • 这样更好。我将其标记为答案,因为它总体上看起来更简单,并且不需要创建自定义函数。
  • 从 Swift 2.0 开始,您可以使用:array.indexOf({$0.name == "Foo"})
  • 从 Swift 3.0 开始,如果需要对象,您可以使用:array.first(where:{$0.name == "Foo"})
  • 如何检查 $0.name 是否包含字符串“foo”?答案是关于精确匹配的。我需要包含字符串。谁能给出那个语法
【解决方案4】:

斯威夫特 3

如果您需要对象使用:

array.first{$0.name == "Foo"}

(如果您有多个名为“Foo”的对象,则first 将返回未指定排序的第一个对象)

【讨论】:

  • 谢谢你。这应该在那儿!
  • 这很好,谢谢!也可以这样写:array.first {$0.name == "Foo"}
  • Swift3 中必须是 array.first(where: {$0.name == "Foo"})
  • 根据 Daniel 的说明,这是 Swift 3 的正确、最佳答案。不要为此使用 map,filter;他们迭代整个集合,这可能会非常浪费。
【解决方案5】:

您可以过滤数组,然后只选择第一个元素,如图所示 在Find Object with Property in Array

或者你定义一个自定义扩展

extension Array {

    // Returns the first element satisfying the predicate, or `nil`
    // if there is no matching element.
    func findFirstMatching<L : BooleanType>(predicate: T -> L) -> T? {
        for item in self {
            if predicate(item) {
                return item // found
            }
        }
        return nil // not found
    }
}

使用示例:

struct T {
    var name : String
}

let array = [T(name: "bar"), T(name: "baz"), T(name: "foo")]

if let item = array.findFirstMatching( { $0.name == "foo" } ) {
    // item is the first matching array element
} else {
    // not found
}

Swift 3 中,您可以使用现有的 first(where:) 方法 (如mentioned in a comment):

if let item = array.first(where: { $0.name == "foo" }) {
    // item is the first matching array element
} else {
    // not found
}

【讨论】:

  • 就效率而言,这与array.lazy.filter( predicate ).first 相比如何? .lazy 对于小型数组的效率如何?
  • @PatNiemeyer:我不知道,您必须衡量性能并进行比较。
  • @PatNiemeyer 上面的解决方案肯定会更有效,即使差异可能不会很大。 1. filter 的复杂度始终为 O(n),而在 findFirstMatching 中,它只是在最坏的情况下(当您要查找的元素是最后一个或根本不在数组中时)。 2. filter 创建一个全新的过滤元素数组,而findFirstMatching 只返回请求的元素。
  • 在 Swift 3 中,我收到错误 Inheritance from non-protocol, non-class type 'Bool'Use of undeclared type 'T' 用于此扩展方法。
  • @Isuru:这个答案很老了,指的是旧的 Swift 版本。在 Swift 3 中,您不再需要自定义扩展方法,我已经相应地更新了答案。
【解决方案6】:

Swift 3.0

if let index = array.index(where: { $0.name == "Foo" }) {
    return array[index]
}

斯威夫特 2.1

swift 2.1 现在支持过滤对象属性。您可以根据结构或类的任何值过滤您的数组,这是一个示例

for myObj in myObjList where myObj.name == "foo" {
 //object with name is foo
}

for myObj in myObjList where myObj.Id > 10 {
 //objects with Id is greater than 10
}

【讨论】:

    【解决方案7】:

    斯威夫特 4

    实现此目的的另一种方法 使用过滤功能,

    if let object = elements.filter({ $0.title == "title" }).first {
        print("found")
    } else {
        print("not found")
    }
    

    【讨论】:

      【解决方案8】:

      斯威夫特 3

      你可以在 Swift 3 中使用 index(where:)

      func index(where predicate: @noescape Element throws -> Bool) rethrows -> Int?
      

      例子

      if let i = theArray.index(where: {$0.name == "Foo"}) {
          return theArray[i]
      }
      

      【讨论】:

      • swift 3中是否有一种方法可以找到满足条件$0.name == "Foo"的数组项子列表的索引?
      【解决方案9】:

      Swift 2 或更高版本

      您可以结合indexOfmap 在一行中编写“查找元素”函数。

      let array = [T(name: "foo"), T(name: "Foo"), T(name: "FOO")]
      let foundValue = array.indexOf { $0.name == "Foo" }.map { array[$0] }
      print(foundValue) // Prints "T(name: "Foo")"
      

      使用filter + first 看起来更干净,但filter 会计算数组中的所有元素。 indexOf + map 看起来很复杂,但是当找到数组中的第一个匹配项时,评估就会停止。这两种方法各有利弊。

      【讨论】:

        【解决方案10】:

        另一种访问 array.index(of: Any) 的方法是声明你的对象

        import Foundation
        class Model: NSObject {  }
        

        【讨论】:

          【解决方案11】:

          斯威夫特 3

          if yourArray.contains(item) {
             //item found, do what you want
          }
          else{
             //item not found 
             yourArray.append(item)
          }
          

          【讨论】:

            【解决方案12】:

            使用contains:

            var yourItem:YourType!
            if contains(yourArray, item){
                yourItem = item
            }
            

            或者您可以在 cmets 中尝试 Martin 指出的内容,然后再试一次 filterFind Object with Property in Array

            【讨论】:

            • 那只会返回一个布尔值吗?我也需要获取对象,而不仅仅是检查是否在数组中。
            • 这假定item 与数组中的项具有相同的类型。然而,我所拥有的只是来自view.annotation.title 的标题。我需要通过这个标题来比较数组中的项目。
            • 类似if contains(yourArray, view.annotation.title) { // code goes here }
            • Martin 在 cmets 中向您展示了另一种方式。检查他提供的链接。
            【解决方案13】:

            斯威夫特 3:

            您可以使用 Swift 的内置功能在数组中查找自定义对象。

            首先,您必须确保您的自定义对象符合:Equatable 协议

            class Person : Equatable { //<--- Add Equatable protocol
                let name: String
                var age: Int
            
                init(name: String, age: Int) {
                    self.name = name
                    self.age = age
                }
            
                //Add Equatable functionality:
                static func == (lhs: Person, rhs: Person) -> Bool {
                    return (lhs.name == rhs.name)
                }
            }
            

            将 Equatable 功能添加到您的对象后,Swift 现在将向您展示可以在数组上使用的其他属性:

            //create new array and populate with objects:
            let p1 = Person(name: "Paul", age: 20)
            let p2 = Person(name: "Mike", age: 22)
            let p3 = Person(name: "Jane", age: 33)
            var people = [Person]([p1,p2,p3])
            
            //find index by object:
            let index = people.index(of: p2)! //finds Index of Mike
            
            //remove item by index:
            people.remove(at: index) //removes Mike from array
            

            【讨论】:

              【解决方案14】:

              对于 Swift 3,

              let index = array.index(where: {$0.name == "foo"})
              

              【讨论】:

                【解决方案15】:

                使用Dollar,即 Lo-Dash 或 Underscore.js 用于 Swift:

                import Dollar
                
                let found = $.find(array) { $0.name == "Foo" }
                

                【讨论】:

                  【解决方案16】:

                  例如,如果我们有一个数字数组:

                  let numbers = [2, 4, 6, 8, 9, 10]
                  

                  我们可以像这样找到第一个奇数:

                  let firstOdd = numbers.index { $0 % 2 == 1 }
                  

                  这会将 4 作为可选整数返回,因为第一个奇数 (9) 在索引 4 处。

                  【讨论】:

                    猜你喜欢
                    • 2015-11-19
                    • 2014-06-07
                    • 2022-10-25
                    • 1970-01-01
                    • 2018-10-27
                    • 2016-06-16
                    • 2015-11-12
                    • 2020-02-07
                    • 2017-04-15
                    相关资源
                    最近更新 更多