Se eu tiver uma coleção c
de tipos T
e houver uma propriedade p
em T
(do tipo P
, digamos), qual é a melhor maneira de fazer uma chave de mapeamento por extração ?
val c: Collection[T]
val m: Map[P, T]
Uma maneira é a seguinte:
m = new HashMap[P, T]
c foreach { t => m add (t.getP, t) }
Mas agora eu preciso de um mapa mutável . Existe uma maneira melhor de fazer isso para que fique em uma linha e acabe com um mapa imutável ? (Obviamente, eu poderia transformar o anterior em um utilitário de biblioteca simples, como faria em Java, mas suspeito que no Scala não há necessidade)
scala
map
scala-collections
oxbow_lakes
fonte
fonte
Traversable[K].mapTo( K => V)
eTraversable[V].mapBy( V => K)
foram melhores!c
porc.iterator
para evitar a criação de coleção intermediária.Você pode construir um mapa com um número variável de tuplas. Portanto, use o método map na coleção para convertê-lo em uma coleção de tuplas e, em seguida, use o truque: _ * para converter o resultado em um argumento variável.
fonte
Além da solução de @James Iry, também é possível fazer isso usando uma dobra. Suspeito que esta solução seja um pouco mais rápida que o método tupla (menos objetos de lixo são criados):
fonte
list.foldLeft(Map[String,Int]()) { (m,s) => m + (s -> s.length) }
. Note que se você quiser usar a vírgula para construir a tupla, você precisa de um par extra de parênteses:((s, s.length))
.Isso pode ser implementado de forma imutável e com uma única passagem, dobrando a coleção da seguinte maneira.
A solução funciona porque a adição a um mapa imutável retorna um novo mapa imutável com a entrada adicional e esse valor serve como acumulador na operação de dobra.
A desvantagem aqui é a simplicidade do código versus sua eficiência. Portanto, para coleções grandes, essa abordagem pode ser mais adequada do que usar 2 implementações transversais, como aplicar
map
etoMap
.fonte
Outra solução (pode não funcionar para todos os tipos)
isso evita a criação da lista intermediária, mais informações aqui: Scala 2.8 breakOut
fonte
O que você está tentando alcançar é um pouco indefinido.
E se dois ou mais itens
c
compartilharem o mesmop
? Qual item será mapeado para aquelep
no mapa?A maneira mais precisa de ver isso é produzir um mapa entre
p
e todos osc
itens que o contêm:Isso pode ser facilmente alcançado com groupBy :
Se você ainda deseja o mapa original, pode, por exemplo, mapear
p
para o primeirot
que o possui:fonte
collect
vez demap
. Por exemplo:c.group(t => t.p) collect { case (Some(p), ts) => p -> ts.head }
. Dessa forma, você pode fazer coisas como nivelar mapas quando digitar é uma opção [_]..mapValues(_.head)
vez do mapa.Provavelmente, essa não é a maneira mais eficiente de transformar uma lista em mapa, mas torna o código de chamada mais legível. Usei conversões implícitas para adicionar um método mapBy à List:
Exemplo de código de chamada:
Observe que, devido à conversão implícita, o código do chamador precisa importar as implitConversions do scala.
fonte
Funciona bem e é muito intuitivo
fonte
c
como chave (mais ou menos). Observe "map" porque a coleção resultante não é uma escala,Map
mas cria outra lista / iterável de tuplas ... mas o efeito é o mesmo para o objetivo do OP, não descartaria a simplicidade, mas não é tão eficiente quanto afoldLeft
solução, nem é a verdadeira resposta para a pergunta "convertendo em uma coleção em um mapa-by-key"Que tal usar zip e toMap?
fonte
Pelo que vale, aqui estão duas maneiras inúteis de fazer isso:
fonte
Map.fromList $ map (bar &&& id) c
,Map.fromList $ map (bar >>= (,)) c
.Isso funciona para mim:
O mapa deve ser mutável e o mapa deve ser retornado, pois a adição a um mapa mutável não retorna um mapa.
fonte
val personsMap = persons.foldLeft(Map[Int, PersonDTO]()) { (m, p) => m + (p.id -> p) }
O Mapa pode ser imutável, como evidenciado acima, porque adicionar a um Mapa imutável retorna um novo Mapa imutável com a entrada adicional. Este valor serve como acumulador através da operação de dobra.use map () na coleção seguido com toMap
fonte
Se estiver convertendo de Json String (lendo um arquivo json) em scala Map
fonte