【问题标题】:Find min / max value in Swift Array在 Swift 数组中查找最小值/最大值
【发布时间】:2014-06-04 11:45:05
【问题描述】:

给定一个 Swift 数值数组,我如何找到最小值和最大值?

到目前为止,我有一个简单(但可能很昂贵)的方法:

var myMax = sort(myArray,>)[0]

以及我在学校是如何被教导这样做的:

var myMax = 0
for i in 0..myArray.count {
    if (myArray[i] > myMax){myMax = myArray[i]}
}

有没有更好的方法从 Swift 中的整数数组中获取最小值或最大值?理想情况下是一行,例如 Ruby 的 .min.max

【问题讨论】:

标签: arrays swift


【解决方案1】:

给定:

let numbers = [1, 2, 3, 4, 5]

斯威夫特 3:

numbers.min() // equals 1
numbers.max() // equals 5

斯威夫特 2:

numbers.minElement() // equals 1
numbers.maxElement() // equals 5

【讨论】:

  • 仅适用于 Comparable 对象,因此例如 NSDecimalNumber 将不起作用。
  • 如果您的数组为空,则返回 0:nums.min() ?? 0
  • 如果你有一个[Int?] 的数组,只需在中间放一个.flatMap{ $0 }.max() :)
【解决方案2】:

要自己计算数组的最小值和最大值,可以使用reduce。这是在 .min().max() 出现在 Swift 之前的关键解决方案。


使用万能的reduce

let nums = [1, 6, 3, 9, 4, 6];
let numMax = nums.reduce(Int.min, { max($0, $1) })

同样:

let numMin = nums.reduce(Int.max, { min($0, $1) })

reduce 获取第一个值,它是内部累加器变量的初始值,然后将传递的函数(这里是匿名的)依次应用于累加器和数组的每个元素,并将新值存储在累加器。然后返回最后一个累加器值。

【讨论】:

  • 完美,正是我想要的。 iBook 中似乎没有很多内容!
  • 这些只是一般的函数式编程技术,它们并不特定于 Swift。
  • @Jean-PhilippePellet 您实际上可以将其简化为:nums.reduce(Int.min, max) 因为max 的原型已经与reduce 期望的类型匹配
  • 这有什么原因不能用于双精度数组吗?
  • 最小/最大函数签名与 combine: 参数签名相匹配,因此您可以只传递函数本身:let numMax = nums.reduce(Int.min, combine: max)
【解决方案3】:

在 Swift 5 中,Array 与其他符合 Sequence 协议的对象(DictionarySet 等)一样,具有两个称为 max()max(by:) 的方法,它们返回序列中的最大元素如果序列为空,则为 nil


#1。使用Arraymax()方法

如果您的序列中的元素类型符合Comparable 协议(可能是StringFloatCharacter 或您的自定义类或结构之一),您将能够使用max()具有以下declaration:

@warn_unqualified_access func max() -> Element?

返回序列中的最大元素。

以下 Playground 代码显示使用 max()

let intMax = [12, 15, 6].max()
let stringMax = ["bike", "car", "boat"].max()

print(String(describing: intMax)) // prints: Optional(15)
print(String(describing: stringMax)) // prints: Optional("car")
class Route: Comparable, CustomStringConvertible {

    let distance: Int
    var description: String { return "Route with distance: \(distance)" }

    init(distance: Int) {
        self.distance = distance
    }

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

    static func <(lhs: Route, rhs: Route) -> Bool {
        return lhs.distance < rhs.distance
    }

}

let routes = [
    Route(distance: 20),
    Route(distance: 30),
    Route(distance: 10)
]

let maxRoute = routes.max()
print(String(describing: maxRoute)) // prints: Optional(Route with distance: 30)

#2。使用Arraymax(by:)方法

如果您的序列中的元素类型不符合Comparable 协议,您将不得不使用具有以下declarationmax(by:)

@warn_unqualified_access func max(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?

返回序列中的最大元素,使用给定的谓词作为元素之间的比较。

以下 Playground 代码显示使用 max(by:)

let dictionary = ["Boat" : 15, "Car" : 20, "Bike" : 40]

let keyMaxElement = dictionary.max(by: { (a, b) -> Bool in
    return a.key < b.key
})

let valueMaxElement = dictionary.max(by: { (a, b) -> Bool in
    return a.value < b.value
})

print(String(describing: keyMaxElement)) // prints: Optional(("Car", 20))
print(String(describing: valueMaxElement)) // prints: Optional(("Bike", 40))
class Route: CustomStringConvertible {

    let distance: Int
    var description: String { return "Route with distance: \(distance)" }

    init(distance: Int) {
        self.distance = distance
    }

}

let routes = [
    Route(distance: 20),
    Route(distance: 30),
    Route(distance: 10)
]

let maxRoute = routes.max(by: { (a, b) -> Bool in
    return a.distance < b.distance
})

print(String(describing: maxRoute)) // prints: Optional(Route with distance: 30)

【讨论】:

  • 在 Swift 3 中“maxElement”已重命名为“max”
【解决方案4】:

其他答案都是正确的,但别忘了你也可以使用集合运算符,如下:

var list = [1, 2, 3, 4]
var max: Int = (list as AnyObject).valueForKeyPath("@max.self") as Int

你也可以用同样的方法求平均值:

var avg: Double = (list as AnyObject).valueForKeyPath("@avg.self") as Double

这种语法可能不如其他一些解决方案清晰,但有趣的是-valueForKeyPath: 仍然可以使用 :)

【讨论】:

    【解决方案5】:

    您可以使用reduce:

    let randomNumbers = [4, 7, 1, 9, 6, 5, 6, 9]
    let maxNumber = randomNumbers.reduce(randomNumbers[0]) { $0 > $1 ? $0 : $1 } //result is 9
    

    【讨论】:

      【解决方案6】:

      Swift 3.0

      您可以通过编程方式尝试此代码。

      func getSmallAndGreatestNumber() -> Void {
      
          let numbers = [145, 206, 116, 809, 540, 176]
          var i = 0
          var largest = numbers[0]
          var small = numbers[0]
          while i < numbers.count{
      
              if (numbers[i] > largest) {
                  largest = numbers[i]
              }
              if (numbers[i] < small) {
                  small = numbers[i]
              }
              i = i + 1
          }
          print("Maximum Number ====================\(largest)")// 809
          print("Minimum Number ====================\(small)")// 116
      }
      

      【讨论】:

        【解决方案7】:

        使用 Swift 1.2(可能更早),您现在需要使用:

        let nums = [1, 6, 3, 9, 4, 6];
        let numMax = nums.reduce(Int.min, combine: { max($0, $1) })
        

        为了处理 Double 值,我使用了这样的东西:

        let nums = [1.3, 6.2, 3.6, 9.7, 4.9, 6.3];
        let numMax = nums.reduce(-Double.infinity, combine: { max($0, $1) })
        

        【讨论】:

        • 你也可以这样做let numMax = nums.reduce(-Double.infinity, combine: max),最大函数签名匹配 combine: 参数签名。
        【解决方案8】:

        在 Swift 2.0 中,minElementmaxElement 成为 SequenceType 协议的方法,你应该这样称呼它们:

        let a = [1, 2, 3]
        print(a.maxElement()) //3
        print(a.minElement()) //1
        

        现在将maxElement 用作maxElement(a) 之类的函数不可用

        Swift 的语法在不断变化,所以我可以在 Xcode version7 beta6 中确认这一点。

        以后可能会修改,所以建议你在使用这些方法之前最好查看一下文档。

        【讨论】:

          【解决方案9】:
          var numbers = [1, 2, 7, 5];    
          var val = sort(numbers){$0 > $1}[0];
          

          【讨论】:

          • 对我来说这看起来很像var myMax = sort(myArray,&gt;)[0]
          • 排序开销太大。
          【解决方案10】:

          这是针对此处发布的解决方案的性能测试。 https://github.com/tedgonzalez/MaxElementInCollectionPerformance

          这是 Swift 5 中最快的

          array.max()

          【讨论】:

            【解决方案11】:

            为 Swift 3/4 更新:

            使用下面的简单代码行从数组中查找最大值;

            var num = [11, 2, 7, 5, 21]
            var result = num.sorted(){
                $0 > $1
            }
            print("max from result: \(result[0])") // 21
            

            【讨论】:

              【解决方案12】:

              只是好奇为什么您认为学校的教学方式可能很昂贵?您正在运行一个时间复杂度为 O(N) 的 for 循环。这实际上比大多数排序算法都要好,并且相当于 reduce 等高阶方法的性能。

              所以我认为,就性能而言,for 循环是最好的。我不认为你会找到比 O(N) 更好的找到最大值的方法。

              当然,只要使用苹果提供的.max()方法即可。

              【讨论】:

              • 我指的是使用排序的那个,当谈到昂贵的时候。
              【解决方案13】:

              如果需要同时最小值和最大值,一种有效的方法是使用带有元组的单个reduce 操作:

              let values = [11, 2, 7, 5, 21]
              
              let (minimum, maximum) = values.reduce((Int.max, Int.min)) {
                  (min($0.0, $1), max($0.1, $1))
              }
              
              print(minimum, maximum) // 2, 21
              

              【讨论】:

                【解决方案14】:

                您还可以对数组进行排序,然后使用array.firstarray.last

                【讨论】:

                猜你喜欢
                • 2018-05-03
                • 2015-04-06
                • 2017-08-18
                • 2021-09-15
                • 2018-08-01
                • 2019-03-31
                • 2016-11-12
                • 1970-01-01
                相关资源
                最近更新 更多