7
votes

Comment joindre une matrice d'entiers optionnels à la chaîne?

donné [INT?], Besoin de construire une chaîne à partir de celui-ci.

Cet extrait de code fonctionne xxx

mais je n'aime pas plattmap suivi de mappe . Y a-t-il une meilleure solution?


0 commentaires

6 Réponses :


3
votes

Si vous n'aimez pas le platmap code> et la carte ensemble, vous pouvez remplacer ce xxx pré>

avec cette p>

let result = [optionalInt1, optionalInt2].flatMap {
        guard let num = $0 else { return nil }
        return String(num)
    }.joined(separator: ",")


3 commentaires

Belle prise! J'ai oublié .description essayer de faire fonctionner les choses avec String (décrivant :) , chaîne ()


Notez que l'équipe SWIFT vous décourage d'accéder directement à la propriété (dernier paragraphe de la vue d'ensemble Dans les docs ) - Bien que j'avoue que cela permet d'appeler un joli appel.


@Hamish: Je ne le savais pas. Merci beaucoup pour l'information.



4
votes

Voici une autre approche:

[optionalInt1, optionalInt2].flatMap { $0.map(String.init) }


6 commentaires

Cette solution fonctionnera également lorsque le type générique de la matrice ne correspond pas à CustomStringConversible ou ne dispose pas d'une propriété (code>.


@Yakivkovalskiy Dans ce cas, il est très évident que 0 $ est .Some (...) si la 2e cible conditionnelle de l'opérateur ternaire est entrée; Un cas particulier où nous pouvons vraiment utiliser ! en toute sécurité et en même temps, sémantiquement, que nous savons ce que nous faisons.


@Yakivkovalskiy Le débit forcé n'est pas nécessairement mauvais. C'est bien utilisé et maltraité, mais c'est parfaitement justifiable dans un cas comme celui-ci


@Alexander Vous avez peut-être raison. À mon avis, il ne faut plus jamais utiliser la force de la force du code SWIFT, mais ce sujet est trop controversé pour discuter ici.


@Yakivkovalskiy jamais est une déclaration assez forte, il y a plusieurs endroits où il n'y a vraiment aucun autre choix, tel que pour les définitions de fermeture récursives


Flatmap a été remplacé par compactmap .



4
votes

Vous pouvez utiliser le mappe code> méthode de en option code> dans un Flatmap CODE> Fermeture appliquée sur le tableau, faisant appel au fait que le premier retournera nil code> sans entrer dans le fermeture fournie dans le cas où la facultative elle-même est nil code>: xxx pré>


aussi, si vous n'enveloppez pas les fermetures de fin (de platmap code>, mappe code>) dans la paranthèse et utilise en outre le fait que la référence d'initialisateur string.init code> sera (dans ce cas) (dans ce cas) non ambigueusement à la correction Chaîne code> initialiseur (tel qu'utilisé ci-dessus), un plat de colonne code> et carte code> ne doit pas avoir l'air "gonflé", et est également une approche entièrement valide ici (la Enchaîné Flatmap CODE> et MAP CODE> Tenez également la valeur pour la sémantique). P>

let unwrappedStrings = [optionalInt1, optionalInt2]
    .flatMap{ $0 }.map(String.init) 


3 commentaires

Mais j'essaie d'éviter l'utilisation de mappe et flatmap ici parce que la boucle via la matrice ne peut pas être bonne.


@Yakivkovalskiy Notez que la première solution ci-dessus utilise la carte Fonctionnement du type facultatif (qui est un seul appel à une méthode d'instance de l'élément optionnel), pas du tableau , donc il n'y aura qu'un seul passage sur le tableau dans celui-là. La première méthode ci-dessus est presque équivalente à @ Solution d'Alexandre ci-dessous . Néanmoins, un platmap et et est toujours o (n) , et je ne vois pas comment cela pourrait jamais être " ne peut pas être bon » sauf si vous travaillez avec une application HPC extrêmement lourde. Sinon, mettez également la mise au point sur la sémantique.


@Yakivkovalsky Si vous souhaitez éviter la boucle répétée, utilisez .lazy . Par exemple. Array.Map (fn1) .Map (FN2) ne lira que les éléments une fois, appliquant chaque fonction successivement, sans copier / stocker des résultats intermédiaires dans des tableaux intermédiaires.



0
votes

Éviter complètement la colonne et la carte. Cependant, créer un var.

let optionalInt1: Int? = 1
let optionalInt2: Int? = nil
let optionalInts = [optionalInt1, optionalInt2]

var strings = [String]()
for optInt in optionalInts {
    if let integer = optInt {
        strings.append(String(integer))
    }
}
let string = strings.joined(separator: ",")


3 commentaires

"Éviter complètement la colonne et la carte" ne fais pas ça.


@ Alexander-Reinstatetemonica puis-je savoir pourquoi?


Toute votre pour La boucle est juste une façon vraiment longue de dire platmap (maintenant appelé compactmap , pour cette variante). Pourquoi réinventer la roue?



2
votes

Les autres réponses utilisent Flatmap CODE> pour éliminer les éléments nil code> et nécessiter un appel sur joint () code> pour combiner les éléments et ajouter les virgules .

en utilisant joint () code> pour ajouter les virgules est bien sûr une seconde passe à travers la déployer. Voici un moyen d'utiliser Réduire code> pour le faire en une seule passe: p> xxx pré>

sortie: p>

let result = arr.reduce(into: "") { (string, elem) in
    guard let elem = elem else { return }
    if string.isEmpty {
        string = String(elem)
    } else {
        string.append(",\(elem)")
    }
}


5 commentaires

(Je suis conscient que c'est une ancienne réponse) Ceci a O (N ^ 2) La complexité du temps (chaque annexe provoquerait une duplication de chaîne), ce qui n'est pas génial. De plus, étant donné que le code est plus complexe que platmap + joint (séparateur: "") , je vous conseillerais fortement. Voir github.com/amomchilov/blog/blob/master / ...


@ Alexander-réinlevstatetemonica, dans une version de la libération d'un tableau de 10 000 éléments avec 10% nil S a pris 0.01 secondes à la fois avec ma réponse et votre dernière personne avec joint (séparateur : ",") . Réécriture d'utiliser Réduire (dans :) et ANNEXE RAN deux fois plus vite. Donc, votre plainte concernant la complexité du code est valide, mais le problème de la rapidité est injustifié.


Mes préoccupations de performance Ces jours-ci sont généralement moins de temps (sauf pour bloquer les appels de réseau, ceux-ci sont toujours un grand non-non), mais plus sur la vie de la batterie. Je ne voudrais pas y mettre beaucoup de temps, mais si c'est trivial (par exemple, mettre un .lazyzy avant une chaîne d'appels), je le ferais à l'avant, juste pour garder l'appareil à avoir besoin de utiliser ses noyaux plus élevés et tels.


@ Alexander-réinlevstatemonica, ajout .lazy pour faire laisse résultat = arr.lazy.compactMap {$ 0.map (String.init)} .joind (séparateur: ",") ralenti le bas de 0.01068 secondes à 0.01469 secondes.


@ Alexander-Reinstatetemonica, oui, c'est une version de sortie.



1
votes

SWIFT3.1

[1,2,3] .flatmap ({String (décrivant: 0)}). Joigné (séparateur: "")

// "1 2 3" (Sans guillemets)


1 commentaires

Cela produit des valeurs de chaîne de en option (1) et nil , ce qui n'est presque certainement pas prévu. Et même si c'est était destiné, cela vaut probablement une forte réexamen.