简体   繁体   English

FirstIndex:of:对象数组中

[英]FirstIndex:of: in an array of objects

I have this class: 我有这个课:

class ValueTimestamp {
  let value: Double
  let timestamp : Double
  init(value:Double, timestamp:Double) {
    self.value = value
    self.timestamp = timestamp
  }
}

then I have an array of objects of this class. 然后我有一个此类的对象数组。

Now I want to scan that array and find the object of ValueTimestamp class with the minimum value. 现在,我想扫描该数组并找到具有最小值的ValueTimestamp类的对象。

Suppose the array has 3 elements 假设数组有3个元素

  1. element1 (value = 12, timestamp = 2) element1 (值= 12,时间戳= 2)
  2. element2 (value = 5 , timestamp = 3) element2 (值= 5,时间戳= 3)
  3. element3 (value = 10, timestamp = 4) element3 (值= 10,时间戳= 4)

and

let myArray = [element1, element2, element3]

now I want to find the element that has the minimum value. 现在我想找到具有最小值的元素。

I supposed this would work 我以为这会工作

let min = myArray.map({$0.value}).min()
let minIndex = myArray.firstIndex(of: min)

but the second line gives me this error 但是第二行给我这个错误

Incorrect argument label in call (have 'of:', expected 'where:') 调用中的参数标签不正确(具有“ of:”,预期为“ where:”)

any ideas? 有任何想法吗?

firstIndex:of: looks for the first element that is equal to the provided argument. firstIndex:of:查找等于提供的参数的第一个元素。 But you aren't looking for an element that's equal to it, you're looking for one whose value property is equal. 但是,您并不是在寻找与之相等的元素,而是在寻找一种其value属性相等的元素。 So you need to use where and provide a function for that instead: 因此,您需要使用where并为此提供功能:

let minIndex = myArray.firstIndex(where: {$0.value == min})

You could also make your class conform to Comparable and call min on it directly: 您还可以使您的类符合Comparable并直接在其上调用min

class ValueTimestamp: Comparable {
  let value: Double
  let timestamp : Double
  init(value:Double, timestamp:Double) {
    self.value = value
    self.timestamp = timestamp
  }

  static func == (lhs: ValueTimestamp, rhs: ValueTimestamp) -> Bool {
    return lhs.value == rhs.value
  }
  static func < (lhs: ValueTimestamp, rhs: ValueTimestamp) -> Bool {
    return lhs.value < rhs.value
  }
}

let minObject = myArray.min()

Note that if it's possible to have two objects with the same value , you may need to adjust the functions to determine which one is "less" in that case. 请注意,如果可能有两个具有相同value对象,则可能需要调整功能以确定在这种情况下哪个“较少”。

firstIndex(of: ) does not work because I presume your class does not conform to Equatable . firstIndex(of: ) Equatable不起作用,因为我认为您的类不符合Equatable

Thats why it is expected from you to use firstIndex(where:) for this case. 这就是为什么您希望firstIndex(where:)这种情况下使用firstIndex(where:)的原因。

Also in the code below you are not getting an object, you are getting the value, so min is type of Double? 同样在下面的代码中,您没有得到对象,而是得到了值,所以minDouble?类型Double? not ValueTimeStamp? 不是ValueTimeStamp? :

let min = myArray.map({$0.value}).min()

You could get the min index with the following with using where: 您可以使用where获得以下内容的最小索引:

let minIndex = myArray.firstIndex(where: {$0.value == min})

References: 参考文献:

https://developer.apple.com/documentation/swift/array/2994720-firstindex https://developer.apple.com/documentation/swift/array/2994722-firstindex https://developer.apple.com/documentation/swift/array/2994720-firstindex https://developer.apple.com/documentation/swift/array/2994722-firstindex

The root cause here is that firstIndex(of:_) is only defined on Collection where Element: Equatable . 根本原因是, firstIndex(of:_)仅在Collection where Element: Equatable定义为Collection where Element: Equatable Your type isn't equatable, so this method isn't available to you, until you make it conform. 您的类型是不平等的,因此直到您使它合规后,您才可以使用此方法。

However, your problem can be more elegantly solved by using Array.enumerated() and Array.min(by:_) : 但是,可以使用Array.enumerated()Array.min(by:_)更好地解决您的问题:

If you only need the element, you can do this: 如果只需要该元素,则可以执行以下操作:

 let timestampedValues = [element1, element2, element3]

 let minTimestampedValue = timestampedValues
      .enumerated()
      .min(by: { $0.value })

print(minTimestampedValue as Any)

If you only need the index, you can do this: 如果只需要索引,则可以执行以下操作:

let minTimestampedValueIndex = timestampedValues
            .enumerated()
            .min(by: { $0.element.value < $1.element.value })?.offset

print(minTimestampedValueIndex as Any)

If you want both, you can do this: 如果两者都需要,则可以执行以下操作:

let minTimestampedValuePair = timestampedValues
                .enumerated()
                .min(by: { $0.element.value < $1.element.value })

print(minTimestampedValuePair.offset as Any, minTimestampedValuePair.element as Any)

All three of these snippets obtain the answer using only a single pass through the array, which makes them twice as fast as the "find the min, then find its index" approach. 所有这三个摘要都仅通过数组一次即可获得答案,这使其比“查找最小值,然后找到其索引”方法快两倍。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM