Je voudrais mapper une fonction sur toutes les touches du dictionnaire. J'espérais que quelque chose comme ce qui suit fonctionnerait, mais le filtre ne peut pas être appliqué directement au dictionnaire. Quelle est la manière la plus propre d'y parvenir?
Dans cet exemple, j'essaie d'incrémenter chaque valeur de 1. Cependant, c'est accessoire pour l'exemple - le but principal est de comprendre comment appliquer map () à un dictionnaire.
var d = ["foo" : 1, "bar" : 2]
d.map() {
$0.1 += 1
}
swift
dictionary
Maria Zverina
la source
la source
map
fait a. ce que vous demandez, c'est un moyen de cacher l'itération derrière une extension / fermeture afin que vous n'ayez pas à la regarder à chaque fois que vous l'utilisez.Réponses:
Swift 4+
Bonnes nouvelles! Swift 4 comprend une
mapValues(_:)
méthode qui construit une copie d'un dictionnaire avec les mêmes clés, mais des valeurs différentes. Il inclut également unefilter(_:)
surcharge qui renvoie aDictionary
, etinit(uniqueKeysWithValues:)
et desinit(_:uniquingKeysWith:)
initialiseurs pour créer un àDictionary
partir d'une séquence arbitraire de tuples. Cela signifie que, si vous souhaitez modifier à la fois les clés et les valeurs, vous pouvez dire quelque chose comme:Il existe également de nouvelles API pour fusionner des dictionnaires, substituer une valeur par défaut aux éléments manquants, regrouper des valeurs (conversion d'une collection en un dictionnaire de tableaux, indexé par le résultat du mappage de la collection sur une fonction), etc.
Au cours de la discussion de la proposition, SE-0165 , qui a introduit ces fonctionnalités, j'ai évoqué cette réponse Stack Overflow à plusieurs reprises, et je pense que le grand nombre de votes positifs a aidé à démontrer la demande. Merci donc pour votre aide à améliorer Swift!
la source
map
qui pourrait produire des clés conflictuelles est toujours utilemap
dans de nombreuses situations. (D'un autre côté, vous pourriez affirmer que mapper uniquement les valeurs est une interprétation naturelle desmap
dictionnaires - à la fois l'exemple de l'affiche d'origine et le mien ne modifient que les valeurs, et conceptuellement,map
sur un tableau ne modifie que les valeurs, pas les indices.)try
:return Dictionary<Key, OutValue>(try map { (k, v) in (k, try transform(v)) })
DictionaryExtension.swift:13:16: Argument labels '(_:)' do not match any available overloads
Argument labels '(_:)' do not match any available overloads
lors de la mise en œuvre de cette dernière extension. Je ne sais pas vraiment comment le résoudre: /Dictionary
initialiseur ajouté dans l'un des exemples précédents. Assurez-vous d'inclure les deux.Avec Swift 5, vous pouvez utiliser l'un des cinq extraits suivants pour résoudre votre problème.
#1. Utilisation de la
Dictionary
mapValues(_:)
méthode# 2. Utilisation de la
Dictionary
map
méthode et de l'init(uniqueKeysWithValues:)
initialiseur# 3. Utilisation d'une
Dictionary
reduce(_:_:)
méthode ou d'unereduce(into:_:)
méthode# 4. Utilisation de l'
Dictionary
subscript(_:default:)
indice# 5. Utilisation de l'
Dictionary
subscript(_:)
indicela source
Alors que la plupart des réponses ici se concentrent sur la façon de mapper l'ensemble du dictionnaire (clés et valeurs), la question ne voulait vraiment mapper que les valeurs. Il s'agit d'une distinction importante car le mappage des valeurs vous permet de garantir le même nombre d'entrées, tandis que le mappage à la fois de la clé et de la valeur peut entraîner des clés en double.
Voici une extension,
mapValues
qui vous permet de mapper uniquement les valeurs. Notez qu'il étend également le dictionnaire avec uneinit
séquence de paires clé / valeur, ce qui est un peu plus général que de l'initialiser à partir d'un tableau:la source
func mapValues<T>(_ transform: (_ value: Value) -> T) -> [Key: T] { var result = [Key: T]() for (key, val) in self { result[key] = transform(val) } return result }
. Je trouve que ça se lit mieux aussi. Y a-t-il un problème de performances?Le moyen le plus simple est d'ajouter simplement
map
au dictionnaire:Vérifier que cela fonctionne:
Production:
la source
SequenceType.map
ne s'agit pas d'une fonction de mutation. Votre exemple pourrait être réécrit pour suivre le contrat existant pourmap
, mais c'est la même chose que la réponse acceptée.Vous pouvez également utiliser à la
reduce
place de la carte.reduce
est capable de faire tout ce que vousmap
pouvez faire et plus encore!Il serait assez facile d'envelopper cela dans une extension, mais même sans l'extension, cela vous permet de faire ce que vous voulez avec un seul appel de fonction.
la source
let newDict = oldDict.reduce([String:Int]()) { (var dict, pair) in dict["new\(pair.1)"] = pair.1; return dict }
Il s'avère que vous pouvez le faire. Ce que vous devez faire est de créer un tableau à partir
MapCollectionView<Dictionary<KeyType, ValueType>, KeyType>
de lakeys
méthode renvoyée par les dictionnaires . ( Info ici ) Vous pouvez ensuite mapper ce tableau et renvoyer les valeurs mises à jour au dictionnaire.la source
Selon la référence de la bibliothèque standard Swift, la carte est une fonction de tableaux. Pas pour les dictionnaires.
Mais vous pouvez parcourir votre dictionnaire pour modifier les clés:
la source
Je cherchais un moyen de mapper un dictionnaire directement dans un tableau typé avec des objets personnalisés. J'ai trouvé la solution dans cette extension:
En l'utilisant comme suit:
la source
Swift 3
J'essaye de manière simple dans Swift 3.
Je veux la carte [Chaîne: Chaîne] à [string: String] , j'utilise forEach au lieu de carte ou d'une carte plat.
la source
Swift 5
La fonction map du dictionnaire est fournie avec cette syntaxe.
dictData.map(transform: ((key: String, value: String)) throws -> T)
vous pouvez simplement définir les valeurs de clôture sur ceci
La sortie sera:
C'est peut-être donner cet avertissement
Result of call to 'map' is unused
Ensuite, définissez juste
_ =
avant la variable.Peut-être que cela vous aidera. Merci.
la source
Je suppose que le problème est de conserver les clés de notre dictionnaire d'origine et de mapper toutes ses valeurs d'une manière ou d'une autre.
Généralisons et disons que nous pouvons vouloir mapper toutes les valeurs vers un autre type .
Nous aimerions donc commencer par un dictionnaire et une fermeture (une fonction) et finir avec un nouveau dictionnaire. Le problème est, bien sûr, que le typage strict de Swift fait obstacle. Une fermeture doit spécifier quel type entre et quel type sort, et donc nous ne pouvons pas faire une méthode qui prend un général fermeture - sauf dans le contexte d'un générique. Nous avons donc besoin d'une fonction générique.
D'autres solutions se sont concentrées sur cela dans le monde générique de la structure générique du dictionnaire lui-même, mais je trouve plus facile de penser en termes de fonction de niveau supérieur. Par exemple, nous pourrions écrire ceci, où K est le type de clé, V1 est le type de valeur du dictionnaire de départ et V2 est le type de valeur du dictionnaire de fin:
Voici un exemple simple de son appel, juste pour prouver que le générique se résout effectivement au moment de la compilation:
Nous avons commencé avec un dictionnaire de
[String:Int]
et retrouvés avec un dictionnaire de[String:String]
en transformant les valeurs du premier dictionnaire par une fermeture.(EDIT: je vois maintenant que c'est effectivement la même chose que la solution AirspeedVelocity, sauf que je n'ai pas ajouté l'élégance supplémentaire d'un initialiseur de dictionnaire qui crée un dictionnaire à partir d'une séquence zip.)
la source
Swift 3
Usage:
Extension:
la source
Si vous essayez uniquement de mapper les valeurs (en changeant potentiellement leur type), incluez cette extension:
Étant donné que vous avez ce dictionnaire:
La transformation de valeur sur une seule ligne ressemble alors à ceci:
La transformation de valeur multiligne ressemble alors à ceci:
la source
Une autre approche consiste à
map
trouver un dictionnaire etreduce
, où les fonctionskeyTransform
etvalueTransform
sont des fonctions.la source
Swift 3 j'ai utilisé ceci,
Usage:
Réf
la source