簡體   English   中英

在 Swift 數組中查找最小值/最大值

[英]Find min / max value in 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 中的 integer 數組中獲取最小值或最大值? 理想情況下是一行,例如 Ruby 的.min.max

鑒於:

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

更新:應該是公認的答案,因為maxElement出現在 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取第一個值作為內部累加器變量的初始值,然后將傳遞的函數(這里是匿名的)依次應用於累加器和數組的每個元素,並將新值存儲在累加器中。 然后返回最后一個累加器值。

在 Swift 5 中, Array與其他符合Sequence協議的對象( DictionarySet等)一樣,有兩個稱為max()max(by:) ,它們返回序列中的最大元素,如果序列為空,則返回nil


#1. 使用Arraymax()方法

如果您的序列中的元素類型符合Comparable協議(可能是StringFloatCharacter或您的自定義類或結構之一),您將能夠使用具有以下聲明的max()

@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協議,則必須使用具有以下聲明的max(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)

其他答案都是正確的,但不要忘記您也可以使用集合運算符,如下所示:

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

您可以使用reduce

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

斯威夫特 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
}
var numbers = [1, 2, 7, 5];    
var val = sort(numbers){$0 > $1}[0];

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

在 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 中確認這一點。

以后可能會修改,所以建議你在使用這些方法之前最好先查看文檔。

這是此處發布的解決方案的性能測試。 https://github.com/tedgonzalez/MaxElementInCollectionPerformance

這是Swift 5 中最快的

array.max()

為 Swift 3/4 更新:

使用以下簡單的代碼行從數組中找到最大值;

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

只是好奇為什么你認為在學校教授的方式可能很貴? 您正在運行一個時間復雜度為 O(N) 的 for 循環。 這實際上比大多數排序算法都要好,並且相當於reduce等高階方法的性能。

所以我認為就性能而言,for 循環已經足夠好了。 我不認為你會找到比 O(N) 更好的東西來尋找最大值。

當然,只用蘋果提供的.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)")

Apple 於 2021 年推出的Swift 算法包含可能高度優化的最小值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)。

您還可以對數組進行排序,然后使用array.firstarray.last

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM