Méthode correcte pour trouver max dans un tableau dans Swift


121

J'ai jusqu'à présent un moyen simple (mais potentiellement coûteux):

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

Et comment on m'a appris à le faire à l'école:

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

Existe-t-il un meilleur moyen d'obtenir la valeur maximale d'un tableau d'entiers dans Swift? Idéalement quelque chose qui est une ligne comme Ruby.max


Vous écrivez une extension.
gnasher729

Oui, une ligne: maxElement(myArray). Voir quelle est actuellement la deuxième réponse (Rudolf Adamkovic) ci-dessous.
leekaiinthesky

Yo change qui a accepté la réponse à ceci
mattgabor

@mattymcgee J'ai mis à jour la réponse acceptée.
Charlie Egan

Réponses:


299

Donné:

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
Fonctionne uniquement sur les Comparableobjets, donc NSDecimalNumberne fonctionnera pas par exemple.
Michał Hernas

2
Est-ce juste moi ou ces fonctions n'existent-elles pas dans Swift 2?
Liron Yahdav

@LironYahdav Ce sont maintenant des méthodes. Fixé. Merci!
Rudolf Adamkovič

2
Notez que dans Swift 3, ils ont été renommés simplement min()et max().
jemmons

1
@Jezzamon Non. Dans Swift 3, les méthodes minElementet maxElementont été renommées minet max. voir: github.com/apple/swift-evolution/blob/master/proposals/...~~V~~singular~~1st Je comprends votre confusion, car les fonctions libres minet maxaussi existent encore. Voir, par exemple, gist.github.com/lorentey/d679064cb29df4558534d619319a1d9e
jemmons

95

Mise à jour: Cela devrait probablement être la réponse acceptée depuis son maxElementapparition dans Swift.


Utilisez le tout-puissant reduce:

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

De même:

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

reduceprend une première valeur qui est la valeur initiale d'une variable d'accumulateur interne, puis applique la fonction passée (ici, c'est anonyme) à l'accumulateur et à chaque élément du tableau successivement, et stocke la nouvelle valeur dans l'accumulateur. La dernière valeur de l'accumulateur est ensuite renvoyée.


1
Parfait, exactement ce que je cherchais. Il y en a beaucoup qui ne figurent pas dans l'iBook, semble-t-il!
Charlie Egan le

2
Ce ne sont que des techniques de programmation fonctionnelle générale, elles ne sont pas spécifiques à Swift.
Jean-Philippe Pellet

10
@ Jean-PhilippePellet vous pouvez en fait simplifier cela à juste: nums.reduce(Int.min, max)puisque maxle prototype du prototype correspond déjà au type reduceattendu
dessiné

y a-t-il une raison pour laquelle cela ne fonctionne pas avec des tableaux de doubles?
Nicholas

3
Les signatures de la fonction min / max correspondent à la signature du paramètre combine: afin que vous puissiez simplement passer la fonction elle-même:let numMax = nums.reduce(Int.min, combine: max)
Leslie Godwin

38

Avec Swift 5, Arraycomme les autres Sequenceobjets conforme au Protocole ( Dictionary, Set, etc.), dispose de deux méthodes appelées max()et max(by:)que l'élément de retour maximale dans la séquence ounil si la séquence est vide.


#1. En utilisantArray la max()méthode de

Si le type d'élément dans votre séquence est conforme au Comparableprotocole (peut - il String, Float, Characterou un de votre classe personnalisée ou struct), vous serez en mesure d'utiliser max()qui a la suivante déclaration :

@warn_unqualified_access func max() -> Element?

Renvoie l'élément maximum de la séquence.

Les codes Playground suivants montrent à utiliser 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. Utilisation de Arrayla max(by:)méthode de

Si le type d'élément dans votre séquence n'est pas conforme au Comparableprotocole, vous devrez utiliser max(by:)qui a la déclaration suivante :

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

Renvoie l'élément maximal de la séquence, en utilisant le prédicat donné comme comparaison entre les éléments.

Les codes Playground suivants montrent à utiliser 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)

Dans Swift 3 "maxElement" a été renommé en "max"
Nicolai Henriksen

16

Les autres réponses sont toutes correctes, mais n'oubliez pas que vous pouvez également utiliser des opérateurs de collecte, comme suit:

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

vous pouvez également trouver la moyenne de la même manière:

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

Cette syntaxe est peut-être moins claire que certaines des autres solutions, mais il est intéressant de voir qu'elle -valueForKeyPath:peut toujours être utilisée :)


11

Vous pouvez utiliser avec 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
Pour moi, cela ressemble beaucoup àvar myMax = sort(myArray,>)[0]
Charlie Egan

3
Le tri a trop de frais généraux.
vy32

4

Avec Swift 1.2 (et peut-être plus tôt), vous devez maintenant utiliser:

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

Pour travailler avec les valeurs Double, j'ai utilisé quelque chose comme ceci:

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
Vous pouvez également faire cela let numMax = nums.reduce(-Double.infinity, combine: max), la signature de la fonction max correspond à la signature du paramètre combine:.
Leslie Godwin

3

Dans Swift 2.0, minElementet maxElementdevenez des méthodes de SequenceTypeprotocole, vous devriez les appeler comme:

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

L'utilisation en maxElementtant que fonction comme maxElement(a)n'est pas disponible pour le moment.

La syntaxe de Swift est en évolution, je peux donc simplement le confirmer dans Xcode version7 beta6 .

Il peut être modifié à l'avenir, donc je suggère que vous fassiez mieux de vérifier la documentation avant d'utiliser ces méthodes.


3

Swift 3.0

Vous pouvez essayer ce code par programme.

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

Mis à jour pour Swift 3/4:

Utilisez ci-dessous de simples lignes de code pour trouver le maximum du tableau;

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

-1

Vous pouvez également trier votre tableau, puis utiliser array.firstouarray.last


5
C'est plus lent en termes de calcul. Vous pouvez trouver le maximum en temps linéaire.
Charlie Egan

Je suis un tout nouveau @CharlieEgan, pouvez-vous expliquer le temps linéaire ou me diriger vers un tutoriel. Merci beaucoup
Saad Ghadir

faire quelques lectures sur la «complexité du temps» ( en.wikipedia.org/wiki/Time_complexity ). Cela vaut également la peine d'être lu: bigocheatsheet.com . Quelques bons exemples travaillés ici: khanacademy.org/computing/computer-science/algorithms
Charlie Egan
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.