Richtiger Weg, um max in einem Array in Swift zu finden


121

Ich habe bisher einen einfachen (aber möglicherweise teuren) Weg:

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

Und wie mir das in der Schule beigebracht wurde:

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

Gibt es eine bessere Möglichkeit, den Maximalwert aus einem ganzzahligen Array in Swift zu erhalten? Idealerweise etwas, das eine Zeile ist, wie Ruby's.max


Sie schreiben eine Erweiterung.
Gnasher729

Ja, eine Zeile : maxElement(myArray). Sehen Sie unten die zweite Antwort (Rudolf Adamkovics).
Leekaiinthesky

Sie ändern diese akzeptierte Antwort auf diese
Frage

@mattymcgee Ich habe die akzeptierte Antwort aktualisiert.
Charlie Egan

Antworten:


299

Gegeben:

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

Swift 3:

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

Swift 2:

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

2
Funktioniert nur mit ComparableObjekten, NSDecimalNumberfunktioniert also zum Beispiel nicht.
Michał Hernas

2
Ist es nur ich oder existieren diese Funktionen in Swift 2 nicht?
Liron Yahdav

@LironYahdav Sie sind jetzt Methoden. Fest. Vielen Dank!
Rudolf Adamkovič

2
Beachten Sie in Swift 3, dass diese in einfach min()und umbenannt wurden max().
Jemmons

1
@Jezzamon Nein. In Swift 3 wurden die Methoden minElementund maxElementin minund umbenannt max. siehe: github.com/apple/swift-evolution/blob/master/proposals/... ich Ihre Verwirrung verstehen, weil die freien Funktionen minund maxauch noch existieren. Siehe zum Beispiel gist.github.com/lorentey/d679064cb29df4558534d619319a1d9e
jemmons

95

Update: Dies sollte wahrscheinlich die akzeptierte Antwort sein, seit maxElementsie in Swift erschienen ist.


Benutze den Allmächtigen reduce:

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

Ähnlich:

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

reduceNimmt einen ersten Wert, der der Anfangswert für eine interne Akkumulatorvariable ist, wendet dann die übergebene Funktion (hier anonym) auf den Akkumulator und jedes Element des Arrays nacheinander an und speichert den neuen Wert im Akkumulator. Der letzte Akkumulatorwert wird dann zurückgegeben.


1
Perfekt, genau das, wonach ich gesucht habe. Es gibt eine Menge, die anscheinend nicht im iBook enthalten ist!
Charlie Egan

2
Dies sind nur allgemeine funktionale Programmiertechniken, sie sind nicht spezifisch für Swift.
Jean-Philippe Pellet

10
@ Jean-PhilippePellet Sie können dies tatsächlich vereinfachen, um nur: nums.reduce(Int.min, max)da maxder Prototyp bereits mit dem Typ übereinstimmt, der reduceerwartet wird
drawag

Gibt es einen Grund, warum dies bei Arrays von Doubles nicht funktioniert?
Nicholas

3
Die Min / Max-Funktionssignaturen stimmen mit der Signatur des Kombinats: Parameters überein, sodass Sie die Funktion selbst übergeben können:let numMax = nums.reduce(Int.min, combine: max)
Leslie Godwin

38

Mit Swift 5, Arraywie auch andere SequenceProtokolle entsprechen Objekte ( Dictionary, Setusw.), hat zwei Methoden aufgerufen max()und max(by:)dass die Rückkehr des maximale Element in der Sequenz oder , nilwenn die Sequenz leer ist .


# 1. Mit Arrayder max()Methode von

Wenn der Elementtyp in Ihrer Sequenz Konform ComparableProtokoll (kann es sein String, Float, Characteroder einer Ihrer benutzerdefinierten Klasse oder Struktur), werden Sie in der Lage zu nutzen , max()dass Folgendes Erklärung :

@warn_unqualified_access func max() -> Element?

Gibt das maximale Element in der Sequenz zurück.

Die folgenden Spielplatzcodes werden angezeigt 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. Mit Arrayder max(by:)Methode von

Wenn der Elementtyp in Ihrer Sequenz nicht dem ComparableProtokoll entspricht, müssen Sie max(by:)Folgendes mit der folgenden Deklaration verwenden :

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

Gibt das maximale Element in der Sequenz zurück, wobei das angegebene Prädikat als Vergleich zwischen Elementen verwendet wird.

Die folgenden Spielplatzcodes werden angezeigt 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)

In Swift 3 wurde "maxElement" in "max" umbenannt
Nicolai Henriksen

16

Die anderen Antworten sind alle richtig, aber vergessen Sie nicht, dass Sie auch Erfassungsoperatoren wie folgt verwenden können:

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

Sie können den Durchschnitt auch auf die gleiche Weise ermitteln:

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

Diese Syntax ist möglicherweise weniger klar als einige der anderen Lösungen, aber es ist interessant zu sehen, dass -valueForKeyPath:sie weiterhin verwendet werden kann :)


11

Sie können verwenden mit 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
Für mich sieht das sehr nachvar myMax = sort(myArray,>)[0]
Charlie Egan

3
Sortieren hat zu viel Aufwand.
vy32

4

Mit Swift 1.2 (und möglicherweise früher) müssen Sie jetzt Folgendes verwenden:

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

Für die Arbeit mit Doppelwerten habe ich ungefähr Folgendes verwendet:

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
Sie können dies auch einfach tun let numMax = nums.reduce(-Double.infinity, combine: max). Die maximale Funktionssignatur entspricht der Signatur des Mähdreschers: Parameters.
Leslie Godwin

3

In Swift 2.0, den minElementund maxElementwerden SequenceTypeProtokollmethoden, sollten Sie sie wie folgt aufrufen:

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

Die Verwendung maxElementals Funktion wie maxElement(a)ist derzeit nicht verfügbar .

Die Syntax von Swift ist im Fluss, daher kann ich dies nur in Xcode Version 7 Beta6 bestätigen .

Es kann in Zukunft geändert werden. Ich empfehle daher, das Dokument zu überprüfen, bevor Sie diese Methoden verwenden.


3

Swift 3.0

Sie können diesen Code programmgesteuert ausprobieren.

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

Aktualisiert für Swift 3/4:

Verwenden Sie die folgenden einfachen Codezeilen, um das Maximum aus dem Array zu ermitteln.

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

-1

Sie können Ihr Array auch sortieren und dann array.firstoder verwendenarray.last


5
Dies ist rechnerisch langsamer. Sie können das Maximum in linearer Zeit finden.
Charlie Egan

Ich bin ein sehr neuer @CharlieEgan. Können Sie die lineare Zeit erklären oder mich auf ein Tutorial verweisen? Vielen Dank
Saad Ghadir

Lesen Sie etwas über 'Zeitkomplexität' ( en.wikipedia.org/wiki/Time_complexity ). Dies ist auch eine Lektüre wert: bigocheatsheet.com . Einige gute Beispiele hier: khanacademy.org/computing/computer-science/algorithms
Charlie Egan
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.