在Swift中在数组中查找最大值的正确方法


121

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

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

以及如何在学校教我如何做:

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

有没有更好的方法从Swift中的整数数组获取最大值?理想情况是诸如Ruby之类的单行代码.max


您编写一个扩展名。
gnasher729 2014年

是的,一行:maxElement(myArray)。请参阅下面的第二个答案(Rudolf Adamkovic's)。
leekaiinthesky

呦变化接受了答案,
mattgabor

@mattymcgee我已经更新了接受的答案。
查理·伊根

Answers:


299

鉴于:

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

2
仅适用于Comparable对象,因此NSDecimalNumber将不起作用。
米哈尔Hernas

2
是我还是这些功能在Swift 2中不存在?
Liron Yahdav 2015年

@LironYahdav他们现在是方法。固定。谢谢!
RudolfAdamkovič15年

2
请注意,在Swift 3中,这些已被重命名为simple min()max()
jemmons,2016年

1
@Jezzamon号。在Swift 3中,方法minElementmaxElement被重命名为minmax。见:github.com/apple/swift-evolution/blob/master/proposals/...我明白你的困惑,因为免费的功能minmax也仍然存在。参见例如gist.github.com/lorentey/d679064cb29df4558534d619319a1d9e
jemmons

95

更新: 可能是自maxElementSwift 以来出现的答案。


使用万能的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获取第一个值,该值是内部累加器变量的初始值,然后将传递的函数(在此为匿名)依次应用于累加器和数组的每个元素,并将新值存储在累加器中。然后返回最后的累加器值。


1
完美,正是我想要的。似乎iBook中没有很多东西!
查理·伊根

2
这些只是一般的函数式编程技术,并非特定于Swift。
Jean-Philippe Pellet 2014年

10
@ Jean-PhilippePellet您实际上可以将其简化为:nums.reduce(Int.min, max)因为max的原型已经与reduce预期的类型相匹配
drewag

为什么这不适用于双精度数组?
尼古拉斯

3
最小/最大函数签名与Combine:参数签名匹配,因此您可以直接传递函数本身:let numMax = nums.reduce(Int.min, combine: max)
Leslie Godwin,2015年

38

与Swift 5 Array一样,与其他Sequence符合协议的对象(DictionarySet等)一样,Swift 5 具有两个调用的方法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)

在Swift 3中,“ maxElement”已重命名为“ max”
Nicolai Henriksen

16

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

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


11

您可以使用reduce

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

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

2
在我看来,这很像var myMax = sort(myArray,>)[0]
Charlie Egan

3
排序有太多的开销。
vy32

4

使用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) })

1
您也可以执行此操作let numMax = nums.reduce(-Double.infinity, combine: max),max函数签名与Combine:参数签名匹配。
莱斯利·戈德温

3

在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中对此进行确认。

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


3

斯威夫特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
}


0

已为Swift 3/4更新:

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

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

-1

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


5
这在计算上较慢。您可以找到线性时间的最大值。
查理·伊根

我是一个非常新的@CharlieEgan,您能解释线性时间还是给我一个教程。非常感谢
Saad Ghadir 2015年

做一些关于“时间复杂度”的阅读(en.wikipedia.org/wiki/Time_complexity)。这也值得一读:bigocheatsheet.com。这里有一些好的例子:khanacademy.org/computing/computer-science/algorithms
Charlie Egan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.