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

Charlie Egan
la source
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
Rudolf Adamkovič
la source
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.

Jean-Philippe Pellet
la source
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)
Imanou Petit
la source
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 :)

Sam
la source
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
Khuong
la source
4
var numbers = [1, 2, 7, 5];    
var val = sort(numbers){$0 > $1}[0];
Androabhay
la source
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) })
Conquête d'Allen
la source
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.

Shi XiuFeng
la source
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
}
Sankalap Yaduraj Singh
la source
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
Kiran jadhav
la source
-1

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

Saad Ghadir
la source
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