3 votes

Assignation des fonctions d'ordre supérieur

J'apprends à connaître les fonctions de haut niveau en Swift (comme .map .filter .reduce...) et les types génériques.

Voici ma fonction :

func max<T: Comparable>(_ array: [T]) -> T {
    var max = 0 as! T

    for value in array {
        if value > max { max = value }
    }

    return max
}

Comment puis-je remplacer ma boucle for par une fonction d'ordre supérieur pour obtenir le même résultat ?

Je cherche à faire quelque chose comme ça (ou mieux) :

max = array.map { $0 > max ? $0 : max }

3voto

JeremyP Points 46808

Réduire !

return array.reduce(nil)
{
    (max: T?, current: T) -> T? in
    guard let max = max else { return current }
    return max > current ? max : current
}

Cela renverra une option, mais c'est probablement raisonnable car vous pourriez passer un tableau vide.

Bien sûr, il y a aussi ceci

https://developer.apple.com/documentation/swift/array/1688806-max

Votre question implique qu'il s'agit d'un exercice d'apprentissage. Voici donc une généralisation de la solution qui utilise des fonctions d'ordre supérieur. Notez que la bibliothèque Swft Strandard contient déjà une fonction qui fait cela.

extension Array 
{
     func pickOne(choose: (Element, Element) -> Element) -> Element?
     {
         return self.reduce(nil)
         {
             (bestSoFar: Element?, current: Element) -> Element? in
             guard let bestSoFar = bestSoFar else { return current }
             return choose(bestSoFar, current)
         }
     }
}

La fonctionnalité de max est donc définie comme suit :

array.pickOne { $0 > $1 ? $0 : $1 }

et min serait

array.pickOne { $0 < $1 ? $0 : $1 }

1voto

Thomas Points 1010

Pour les entiers, vous devez utiliser reduce pour ce faire :

// Reduce with initial value the first value of the array if available,
// or 0 otherwise
let max = array.reduce(array.first ?? 0) { (max, newValue) -> T in
    return newValue > max ? newValue : max 
}

MISE À JOUR

Vous voulez la réponse de JeremyP pour un traitement adéquat de tous les comparables !

1voto

Martin R Points 105727

Notez tout d'abord que votre approche de la "valeur initiale" et du "cast" forcé n'a rien à voir avec l'approche de la "valeur initiale". forcée

var max = 0 as! T

a deux problèmes :

  • Il se plantera pour les tableaux ne contenant pas d'entiers, par exemple max(["a", "b"] ).
  • Même pour les tableaux d'entiers, c'est une erreur si tous les éléments du tableau sont des négatifs, par exemple max([-2, -3]) devrait être -2 et non zéro.

Il est donc préférable de choisir le premier élément du tableau comme valeur initiale plutôt que le "zéro forcé".

Cela nous amène à la question suivante : Que se passe-t-il si le tableau est vide ? Il existe deux approches valables : Vous pouvez exiger que le fonction soit appelée avec un tableau non vide (et documenter cette cette condition préalable) :

/// Compute the maximal element in an array.
///
/// - Returns: The maximal element.
///
/// - Note: The array must not be empty.
func max<T: Comparable>(_ array: [T]) -> T {
    precondition(!array.isEmpty, "`max` called with empty array")

    var max = array[0]
    for value in array {
        if value > max { max = value }
    }
    return max
}

Ou bien (comme suggéré dans les autres réponses) faire en sorte que la valeur de retour soit optionnelle :

/// Compute the maximal element in an array.
///
/// - Returns: `nil` if the array is empty, and the maximal element otherwise.
func max<T: Comparable>(_ array: [T]) -> T? {

    guard var max = array.first else { return nil }
    for value in array {
        if value > max { max = value }
    }
    return max
}

Les deux approches peuvent être mises en œuvre avec reduce() . Le premier serait

/// Compute the maximal element in an array.
///
/// - Returns: The maximal element.
///
/// - Note: The array must not be empty.
func max<T: Comparable>(_ array: [T]) -> T {
    precondition(!array.isEmpty, "`max` called with empty array")
    return array.reduce(array[0]) { $0 > $1 ? $0 : $1 }
}

et le second

/// Compute the maximal element in an array.
///
/// - Returns: `nil` if the array is empty, and the maximal element otherwise.
func max<T: Comparable>(_ array: [T]) -> T? {
    guard let first = array.first else { return nil }
    return array.reduce(first) { $0 > $1 ? $0 : $1 }
}

Il est possible de raccourcir encore ce délai à l'aide de la fonction flatMap() méthode de Optional :

/// Compute the maximal element in an array.
///
/// - Returns: `nil` if the array is empty, and the maximal element otherwise.
func max<T: Comparable>(_ array: [T]) -> T? {
    return array.first.flatMap { array.reduce($0) { $0 > $1 ? $0 : $1 } }
}

Enfin, vous pouvez utiliser l'outil existant

func max<T : Comparable>(_ x: T, _ y: T) -> T

au lieu d'une fermeture littérale dans tous les exemples ci-dessus, par exemple

/// Compute the maximal element in an array.
///
/// - Returns: `nil` if the array is empty, and the maximal element otherwise.
func max<T: Comparable>(_ array: [T]) -> T? {
    return array.first.flatMap { array.reduce($0, max) }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X