Me gustaría asignar una función en todas las teclas del diccionario. Esperaba que algo como lo siguiente funcionara, pero el filtro no se puede aplicar al diccionario directamente. ¿Cuál es la forma más limpia de lograr esto?
En este ejemplo, estoy tratando de incrementar cada valor en 1. Sin embargo, esto es incidental para el ejemplo: el objetivo principal es descubrir cómo aplicar map () a un diccionario.
var d = ["foo" : 1, "bar" : 2]
d.map() {
$0.1 += 1
}
swift
dictionary
Maria Zverina
fuente
fuente
map
hace. lo que está pidiendo es una forma de ocultar la iteración detrás de una extensión / cierre para que no tenga que mirarla cada vez que la use.Respuestas:
Swift 4+
¡Buenas noticias! Swift 4 incluye un
mapValues(_:)
método que construye una copia de un diccionario con las mismas claves, pero con valores diferentes. También incluye unafilter(_:)
sobrecarga que devuelve unDictionary
,init(uniqueKeysWithValues:)
einit(_:uniquingKeysWith:)
inicializadores para crear un aDictionary
partir de una secuencia arbitraria de tuplas. Eso significa que, si desea cambiar las claves y los valores, puede decir algo como:También hay nuevas API para fusionar diccionarios, sustituir un valor predeterminado por elementos faltantes, agrupar valores (convertir una colección en un diccionario de matrices, clave por el resultado de asignar la colección sobre alguna función), y más.
Durante la discusión de la propuesta, SE-0165 , que introdujo estas características, mencioné varias veces esta respuesta de Desbordamiento de pila, y creo que la gran cantidad de votos positivos ayudó a demostrar la demanda. ¡Gracias por su ayuda para mejorar Swift!
fuente
map
que pueda producir claves en conflicto sigue siendo útilmap
en muchas situaciones. (Por otro lado, podría argumentar que mapear solo los valores es una interpretación natural de losmap
diccionarios; tanto el ejemplo del póster original como el mío solo modifican los valores, y conceptualmente,map
en una matriz solo modifica los valores, no los índices).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
al implementar esa última extensión. No estoy seguro de cómo resolverlo: /Dictionary
inicializador agregado en uno de los ejemplos anteriores. Asegúrate de incluir ambos.Con Swift 5, puede usar uno de los cinco fragmentos siguientes para resolver su problema.
# 1 Utilizando el
Dictionary
mapValues(_:)
método# 2 Usando
Dictionary
map
método einit(uniqueKeysWithValues:)
inicializador# 3 Usando
Dictionary
reduce(_:_:)
método oreduce(into:_:)
método# 4. Usando
Dictionary
subscript(_:default:)
subíndice# 5. Usando
Dictionary
subscript(_:)
subíndicefuente
Si bien la mayoría de las respuestas aquí se centran en cómo mapear todo el diccionario (claves y valores), la pregunta realmente solo quería mapear los valores. Esta es una distinción importante ya que los valores de mapeo le permiten garantizar el mismo número de entradas, mientras que el mapeo de clave y valor puede resultar en claves duplicadas.
Aquí hay una extensión
mapValues
que le permite mapear solo los valores. Tenga en cuenta que también extiende el diccionario coninit
una secuencia de pares clave / valor, que es un poco más general que inicializarlo desde una matriz:fuente
func mapValues<T>(_ transform: (_ value: Value) -> T) -> [Key: T] { var result = [Key: T]() for (key, val) in self { result[key] = transform(val) } return result }
? Me parece que también se lee mejor. ¿Hay algún problema de rendimiento?La forma más limpia es simplemente agregar
map
al Diccionario:Comprobando que funciona:
Salida:
fuente
SequenceType.map
no es una función mutante. Su ejemplo podría reescribirse para seguir el contrato existentemap
, pero eso es lo mismo que la respuesta aceptada.También puede usar en
reduce
lugar de mapa.reduce
¡es capaz de hacer cualquier cosa quemap
pueda hacer y más!Sería bastante fácil incluir esto en una extensión, pero incluso sin la extensión te permite hacer lo que quieras con una llamada de función.
fuente
let newDict = oldDict.reduce([String:Int]()) { (var dict, pair) in dict["new\(pair.1)"] = pair.1; return dict }
Resulta que puedes hacer esto. Lo que debe hacer es crear una matriz a
MapCollectionView<Dictionary<KeyType, ValueType>, KeyType>
partir delkeys
método devuelto por los diccionarios . ( Información aquí ) Luego puede asignar esta matriz y pasar los valores actualizados al diccionario.fuente
De acuerdo con la Referencia de la biblioteca estándar de Swift, el mapa es una función de las matrices. No es para diccionarios.
Pero podría iterar su diccionario para modificar las claves:
fuente
Estaba buscando una manera de mapear un diccionario directamente en una matriz escrita con objetos personalizados. Encontró la solución en esta extensión:
Usándolo de la siguiente manera:
fuente
Swift 3
Intento una manera fácil en Swift 3.
Quiero mapa [Cadena: Cadena] a [Cadena: Cadena] , yo uso forEach en lugar de mapa o un mapa plano.
fuente
Swift 5
La función de mapa del diccionario viene con esta sintaxis.
dictData.map(transform: ((key: String, value: String)) throws -> T)
solo puede establecer valores de cierre para esto
La salida será ::
Se puede dar esta advertencia
Result of call to 'map' is unused
Luego, simplemente establezca
_ =
antes de la variable.Puede ser que te ayude. Gracias.
fuente
Supongo que el problema es mantener las claves de nuestro diccionario original y asignar todos sus valores de alguna manera.
Permítanos generalizar y decir que podemos querer asignar todos los valores a otro tipo .
Entonces, lo que nos gustaría comenzar es un diccionario y un cierre (una función) y terminar con un nuevo diccionario. El problema es, por supuesto, que la mecanografía estricta de Swift se interpone en el camino. Un cierre necesita especificar qué tipo entra y qué tipo sale, y por lo tanto no podemos hacer un método que tome un cierre general , excepto en el contexto de un genérico. Por lo tanto, necesitamos una función genérica.
Otras soluciones se han concentrado en hacer esto dentro del mundo genérico de la estructura genérica del Diccionario en sí, pero me resulta más fácil pensar en términos de una función de nivel superior. Por ejemplo, podríamos escribir esto, donde K es el tipo de clave, V1 es el tipo de valor del diccionario inicial y V2 es el tipo de valor del diccionario final:
Aquí hay un ejemplo simple de llamarlo, solo para demostrar que el genérico realmente se resuelve en tiempo de compilación:
Comenzamos con un diccionario de
[String:Int]
y terminamos con un diccionario de[String:String]
transformando los valores del primer diccionario a través de un cierre.(EDITAR: ahora veo que esto es efectivamente lo mismo que la solución AirspeedVelocity, excepto que no agregué la elegancia adicional de un inicializador de Diccionario que hace que un Diccionario sea una secuencia zip).
fuente
Swift 3
Uso:
Extensión:
fuente
Si solo está tratando de asignar los valores (potencialmente cambiando su tipo), incluya esta extensión:
Dado que tienes este diccionario:
La transformación del valor de una sola línea se ve así:
La transformación del valor de varias líneas se ve así:
fuente
Otro enfoque es para
map
un diccionario yreduce
, donde funcioneskeyTransform
yvalueTransform
son funciones.fuente
Swift 3 usé esto,
Uso:
Árbitro
fuente