Eu gostaria de mapear uma função em todas as teclas do dicionário. Eu esperava que algo como o seguinte funcionasse, mas o filtro não pode ser aplicado diretamente ao dicionário. Qual é a maneira mais limpa de conseguir isso?
Neste exemplo, estou tentando incrementar cada valor em 1. No entanto, isso é incidental para o exemplo - o objetivo principal é descobrir como aplicar map () a um dicionário.
var d = ["foo" : 1, "bar" : 2]
d.map() {
$0.1 += 1
}
swift
dictionary
Maria Zverina
fonte
fonte
map
faz. o que você está pedindo é uma maneira de ocultar a iteração atrás de uma extensão / fechamento, para que você não precise examiná-la toda vez que a usar.Respostas:
Swift 4+
Boas notícias! O Swift 4 inclui um
mapValues(_:)
método que constrói uma cópia de um dicionário com as mesmas chaves, mas com valores diferentes. Também inclui umafilter(_:)
sobrecarga que retorna umDictionary
, einit(uniqueKeysWithValues:)
einit(_:uniquingKeysWith:)
inicializadores para criar umaDictionary
a partir de uma sequência arbitrária de tuplos. Isso significa que, se você deseja alterar as chaves e os valores, pode dizer algo como:Também existem novas APIs para mesclar dicionários, substituindo um valor padrão por elementos ausentes, agrupando valores (convertendo uma coleção em um dicionário de matrizes, codificado pelo resultado do mapeamento da coleção sobre alguma função) e muito mais.
Durante a discussão da proposta, SE-0165 , que introduziu esses recursos, eu trouxe essa resposta do Stack Overflow várias vezes e acho que o grande número de upvotes ajudou a demonstrar a demanda. Então, obrigado pela sua ajuda para tornar o Swift melhor!
fonte
map
que poderia produzir chaves conflitantes ainda é útilmap
em muitas situações. (Por outro lado, você poderia argumentar que o mapeamento apenas dos valores é uma interpretação natural dosmap
dicionários - o exemplo do pôster original e o meu apenas modificam os valores e, conceitualmente,map
em uma matriz modifica apenas os valores, não os í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
implementar essa última extensão. Não tenho muita certeza de como resolvê-lo: /Dictionary
inicializador adicionado em um dos exemplos anteriores. Certifique-se de incluir os dois.Com o Swift 5, você pode usar um dos cinco trechos a seguir para resolver seu problema.
# 1 Usando o
Dictionary
mapValues(_:)
método# 2 Usando
Dictionary
map
método einit(uniqueKeysWithValues:)
inicializador# 3 Usando
Dictionary
reduce(_:_:)
método oureduce(into:_:)
método# 4 Usando
Dictionary
subscript(_:default:)
subscrito# 5 Usando
Dictionary
subscript(_:)
subscritofonte
Enquanto a maioria das respostas aqui se concentra em como mapear o dicionário inteiro (chaves e valores), a pergunta realmente queria apenas mapear os valores. Essa é uma distinção importante, pois os valores de mapeamento permitem garantir o mesmo número de entradas, enquanto o mapeamento de chave e valor pode resultar em chaves duplicadas.
Aqui está uma extensão,
mapValues
que permite mapear apenas os valores. Observe que ele também estende o dicionário com umainit
sequência de pares de chave / valor, o que é um pouco mais geral do que inicializá-lo a partir de uma matriz:fonte
func mapValues<T>(_ transform: (_ value: Value) -> T) -> [Key: T] { var result = [Key: T]() for (key, val) in self { result[key] = transform(val) } return result }
. Acho que lê melhor também. Existe um problema de desempenho?A maneira mais limpa é adicionar
map
ao Dicionário:Verificando se funciona:
Resultado:
fonte
SequenceType.map
não é uma função mutante. Seu exemplo pode ser reescrito para seguir o contrato existentemap
, mas é o mesmo que a resposta aceita.Você também pode usar em
reduce
vez do mapa.reduce
é capaz de fazer qualquer coisamap
pode fazer e muito mais!Seria bastante fácil agrupar isso em um ramal, mas mesmo sem o ramal, você poderá fazer o que quiser com uma chamada de função.
fonte
let newDict = oldDict.reduce([String:Int]()) { (var dict, pair) in dict["new\(pair.1)"] = pair.1; return dict }
Acontece que você pode fazer isso. O que você precisa fazer é criar uma matriz a
MapCollectionView<Dictionary<KeyType, ValueType>, KeyType>
partir dokeys
método retornado pelos dicionários . ( Informações aqui ) Você pode mapear essa matriz e passar os valores atualizados de volta ao dicionário.fonte
De acordo com a Referência da biblioteca padrão da Swift, o mapa é uma função de matrizes. Não para dicionários.
Mas você pode iterar seu dicionário para modificar as chaves:
fonte
Eu estava procurando uma maneira de mapear um dicionário diretamente em uma matriz digitada com objetos personalizados. Encontrou a solução nesta extensão:
Utilizando-o da seguinte maneira:
fonte
Swift 3
Eu tento uma maneira fácil no Swift 3.
Quero mapear [String: String?] Para [String: String] , uso forEach em vez de map ou flat map.
fonte
Swift 5
A função map do dicionário vem com esta sintaxe.
dictData.map(transform: ((key: String, value: String)) throws -> T)
você pode apenas definir valores de fechamento para isso
A saída será:
Pode ser esse aviso
Result of call to 'map' is unused
Em seguida, basta definir
_ =
antes da variável.Pode ser que ele irá ajudá-lo Obrigado.
fonte
Suponho que o problema é manter as chaves do nosso dicionário original e mapear todos os seus valores de alguma forma.
Vamos generalizar e dizer que podemos querer mapear todos os valores para outro tipo .
Então, o que gostaríamos de começar é um dicionário e um fechamento (uma função) e terminamos com um novo dicionário. O problema é, é claro, que a digitação estrita de Swift atrapalha. Um fechamento precisa especificar qual tipo entra e qual sai, e, portanto, não podemos criar um método que faça um fechamento geral - exceto no contexto de um genérico. Portanto, precisamos de uma função genérica.
Outras soluções se concentraram em fazer isso dentro do mundo genérico da estrutura genérica do Dicionário, mas acho mais fácil pensar em termos de uma função de nível superior. Por exemplo, podemos escrever isso, onde K é o tipo de chave, V1 é o tipo de valor do dicionário inicial e V2 é o tipo de valor do dicionário final:
Aqui está um exemplo simples de chamá-lo, apenas para provar que o genérico realmente se resolve em tempo de compilação:
Começamos com um dicionário de
[String:Int]
e terminamos com um dicionário de[String:String]
, transformando os valores do primeiro dicionário por meio de um fechamento.(EDIT: Agora vejo que isso é efetivamente o mesmo que a solução da AirspeedVelocity, exceto que eu não adicionei a elegância extra de um inicializador de dicionário que transforma um dicionário em uma sequência zip.)
fonte
Swift 3
Uso:
Extensão:
fonte
Se você está apenas tentando mapear os valores (potencialmente alterando seu tipo), inclua esta extensão:
Como você tem este dicionário:
A transformação de valor de linha única fica assim:
A transformação de valor de várias linhas fica assim:
fonte
Outra abordagem é a
map
de um dicionário ereduce
, em que funçõeskeyTransform
evalueTransform
são funções.fonte
Swift 3 eu usei isso,
Uso:
Ref.
fonte