【问题标题】:Find Object with Property in Array在数组中查找具有属性的对象
【发布时间】:2014-11-22 06:39:56
【问题描述】:

是否有可能从具有特定属性的数组中获取对象?或者我是否需要循环遍历数组中的所有对象并检查某个属性是否是我正在寻找的特定属性?

编辑:感谢您给了我正确的方向,但我在转换它时遇到了问题。

// 再次编辑:好的,如果只有一个特定的结果?这也是一种可能的方法吗?

let imageUUID = sender.imageUUID


let questionImageObjects = self.formImages[currentSelectedQuestion.qIndex] as [Images]!

    // this is working
    //var imageObject:Images!
    /*
    for (index, image) in enumerate(questionImageObjects) {

        if(image.imageUUID == imageUUID) {
            imageObject = image
        }

    }
    */

// this is not working - NSArray is not a subtype of Images- so what if there is only 1 possible result?
var imageObject = questionImageObjects.filter( { return $0.imageUUID == imageUUID } )

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    这是 Swift 5

    中的一个工作示例
    class Point{
        var x:Int
        var y:Int
        
        init(x:Int, y:Int){
            self.x = x
            self.y = y
        }
    }
    
    var p1 = Point(x:1, y:2)
    var p2 = Point(x:2, y:3)
    var p3 = Point(x:1, y:4)
    var points = [p1, p2, p3]
    
    // Find the first object with given property
    // In this case, firstMatchingPoint becomes p1
    let firstMatchingPoint = points.first{$0.x == 1}
    
    // Find all objects with given property
    // In this case, allMatchingPoints becomes [p1, p3]
    let allMatchingPoints = points.filter{$0.x == 1}
    

    参考: Trailing Closure

    【讨论】:

      【解决方案2】:

      // 这不起作用 - NSArray 不是 Images 的子类型 - 如果只有 1 个可能的结果怎么办?

      您无法在编译时证明数组上只有一个可能的结果。您实际要求的是 first 匹配结果。最简单的(虽然不是最快的)是只取过滤器结果的第一个元素:

      let imageObject = questionImageObjects.filter{ $0.imageUUID == imageUUID }.first
      

      imageObject 现在当然是可选的,因为可能没有匹配项。

      如果搜索整个数组很耗时,当然您可以轻松创建一个 firstMatching 函数,该函数将返回与闭包匹配的(可选)第一个元素,但对于短数组,这很好而且很简单。


      正如查尔斯所说,在 Swift 3 中,这是内置的:

      questionImageObjects.first(where: { $0.imageUUID == imageUUID })
      

      【讨论】:

      • 你可以在中间添加 lazy 函数,所以它应该只扫描数组直到第一个匹配,并避免你正确提到的性能问题:let imageObject = questionImageObjects.lazy.filter{ $0.imageUUID == imageUUID }.first
      • 其实questionImageObjects.first(where: { $0.imageUUID == imageUUID }) 可能是 swift 3 的方式
      【解决方案3】:

      这是通过使用对象属性在数组中搜索对象来获取特定对象的另一种方法。

      if arrayTicketsListing.contains({ $0.status_id == "2" }) {
            let ticketStatusObj: TicketsStatusList = arrayTicketsListing[arrayTicketsListing.indexOf({ $0.status_id == "2" })!]
            print(ticketStatusObj.status_name)
      }  
      

      然而,我的 arrayTicketsListing 是 [TicketsStatusList] 包含 TicketsStatusList 类的对象。

      // TicketsStatusList class
      
      class TicketsStatusList {
          internal var status_id: String
          internal var status_name: String
          init(){
              status_id = ""
              status_name = ""
          }
      }
      

      【讨论】:

        【解决方案4】:

        编辑 2016-05-05: Swift 3 将包含 first(where:)

        在 Swift 2 中,您可以使用 indexOf 查找与谓词匹配的第一个数组元素的索引。

        let index = questionImageObjects.indexOf({$0.imageUUID == imageUUID})
        

        这比filter 快一点,因为它会在第一场比赛后停止。 (或者,您可以使用lazy 序列。)

        但是,您只能获取索引而不能获取对象本身,这有点烦人。为方便起见,我使用以下扩展名:

        extension CollectionType {
            func find(@noescape predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Self.Generator.Element? {
                return try indexOf(predicate).map({self[$0]})
            }
        }
        

        然后以下工作:

        questionImageObjects.find({$0.imageUUID == imageUUID})
        

        【讨论】:

          【解决方案5】:

          是的,您可以使用 filter 方法,该方法采用闭包,您可以在其中设置逻辑表达式。

          例子:

          struct User {
              var firstName: String?
              var lastName: String?
          }
          
          let users = [User(firstName: "John", lastName: "Doe"), User(firstName: "Bill", lastName: "Clinton"), User(firstName: "John", lastName: "Travolta")];
          
          let johns = users.filter( { return $0.firstName == "John" } )
          

          请注意,filter 返回一个数组,其中包含满足逻辑表达式的所有项。

          更多信息在Library Reference

          【讨论】:

          • 你也可以使用 NSPredicate 和使用 NSarray。
          • 如何过滤名字和姓氏?
          • @Kaptain:这应该很简单:将return $0.firstName == "John" 替换为return $0.firstName == "John" && $0.lastName == "Doe"。换句话说,只需重写/扩展传递给过滤器的闭包,确定何时应该包含元素
          猜你喜欢
          • 2014-05-05
          • 1970-01-01
          • 1970-01-01
          • 2014-05-07
          • 2013-11-23
          • 1970-01-01
          • 2018-11-03
          • 2013-05-06
          • 2018-04-25
          相关资源
          最近更新 更多