在 Swift Array 中查找最小/最大值

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

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

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

还有我在学校是怎么学会的:

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

在 Swift 中,有没有更好的方法从整数 Array 中获得最小值或最大值?理想情况下是一行代码,比如 Ruby 的 .min.max

136270 次浏览

要自己计算数组的最小值和最大值,可以使用 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获取第一个值,该值是内部累加器变量的初始值,然后将传递的函数(在这里是匿名的)依次应用于累加器和数组的每个元素,并将新值存储在累加器中。然后返回最后一个累加器值。

var numbers = [1, 2, 7, 5];
var val = sort(numbers){$0 > $1}[0];

其他的答案都是正确的,但是不要忘记你也可以使用集合运算符,如下所示:

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:仍然可以使用:)

给出:

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

在 Swift 1.2(也许更早)中,你现在需要使用:

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

对于使用 Double value,我使用了如下代码:

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

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

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

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

使用 maxElement作为类似于 maxElement(a)的函数现在是 没空

Swift 的语法不断变化,所以我可以在 Xcode 版本7 beta 6中确认这一点。

将来可能会对它进行修改,所以我建议您在使用这些方法之前最好检查一下文档。

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


# 1. 使用 Arraymax()方法

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

@warn_unqualified_access func max() -> Element?

返回序列中的最大元素。

以下游乐场代码显示使用 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协议,则必须使用具有以下 声明max(by:):

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

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

以下游乐场代码显示使用 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)

你可以和 reduce一起使用:

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

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
}

更新于 Swift 3/4:

使用下面的简单代码行来查找数组中的 max;

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

下面是张贴在这里的解决方案的性能测试

这是 Swift 5最快的

array.max()

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

因此,我认为就性能而言,for 循环已经足够好了。我觉得你找不到比 O (N)更适合找 Max 的了。

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

如果需要 都有的最小值和最大值,一种有效的方法是使用带有元组的单个 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
let array: [Int] = [2, -22, -1, -5600, 333, -167]
var min = 0
var max = array[0]


for i in array {
// finding the min
if min > i {
min = i
}
// finding the max
if max < i {
max = i
}
}


print("Minimum: \(min)\nMaximum: \(max)")

苹果公司2021年推出的 快速算法包含 Minima and/or Maxima,这可能是高度优化。

文档中的例子:

let numbers = [7, 1, 6, 2, 8, 3, 9]
if let (smallest, largest) = numbers.minAndMax(by: <) {
// Work with 1 and 9....
}

总复杂度为 O (k log k + nk) ,如果 k 很小,那么将导致运行时接近 O (n)。如果 k 的数量很大(超过集合的10%) ,我们就回到对整个数组进行排序。实际上,这意味着最坏的情况实际上是 O (n log n)。