Não sei se existe uma maneira adequada de obter o tamanho de uma lista em scala, mas para a sua situação, você poderia usar uma sequência.
Qusay Fantazia
Esta pergunta ainda não foi respondida? Perguntar porque você pode ter esquecido de aceitar um.
Tobias Kolb
Respostas:
150
Uma versão um pouco mais limpa de uma das outras respostas é:
val s =Seq("apple","oranges","apple","banana","apple","oranges","oranges")
s.groupBy(identity).mapValues(_.size)
dando um Mapcom uma contagem para cada item na sequência original:
Map(banana ->1, oranges ->3, apple ->3)
A questão pergunta como encontrar a contagem de um item específico. Com essa abordagem, a solução exigiria o mapeamento do elemento desejado para seu valor de contagem da seguinte maneira:
É a função de identidade, conforme discutido aqui . A função groupByrequer uma função que se aplica aos elementos para saber como agrupá-los. Uma alternativa para agrupar as strings na resposta por suas identidades poderia ser, digamos, agrupar por seu comprimento ( groupBy(_.size)) ou por sua primeira letra ( groupBy(_.head)).
ohruunuruus
2
A desvantagem é que muitas coleções inúteis (porque apenas o tamanho é necessário) são criadas.
Yann Moisan
e se eu quisesse definir um mapa de acumulador nessa expressão em vez de criar um novo mapa?
Uma versão um pouco mais limpa és.groupBy(identity).mapValues(_.size)
ohruunuruus
1
@ohruunuruus isso deve ser uma resposta (vs comentário); adoraria votar positivamente com entusiasmo, se fosse (e selecioná-la como a melhor resposta se eu fosse o OP);
doug
1
@doug um pouco novo no SO e não tinha certeza, mas feliz em obrigar
ohruunuruus
27
list.groupBy(i=>i).mapValues(_.size)
dá
Map[Int,Int]=Map(1->1,2->3,7->1,3->1,4->3)
Observe que você pode substituir (i=>i)pela identityfunção integrada :
val list =List(1,2,4,2,4,7,3,2,4)// Using the provided count method this would yield the occurrences of each value in the list:
l map(x => l.count(_ == x))List[Int]=List(1,3,3,3,3,1,1,3,3)// This will yield a list of pairs where the first number is the number from the original list and the second number represents how often the first number occurs in the list:
l map(x =>(x, l.count(_ == x)))// outputs => List[(Int, Int)] = List((1,1), (2,3), (4,3), (2,3), (4,3), (7,1), (3,1), (2,3), (4,3))
Bom, isso é o que eu estava procurando, achei triste que até mesmo fluxos de Java (que não são bons em alguns aspectos) permitem isso em uma única passagem, enquanto Scala não podia.
Dici
9
Tive o mesmo problema, mas queria contar vários itens de uma vez.
val s =Seq("apple","oranges","apple","banana","apple","oranges","oranges")
s.foldLeft(Map.empty[String,Int]){(m, x)=> m +((x, m.getOrElse(x,0)+1))}
res1: scala.collection.immutable.Map[String,Int]=Map(apple ->3, oranges ->3, banana ->1)
É interessante notar que o mapa com valor padrão 0, intencionalmente projetado para este caso, demonstra o pior desempenho (e não tão conciso quanto groupBy)
Desconfio um pouco desse benchmark, pois não está claro qual é o tamanho dos dados. A groupBysolução tem um desempenho, toLowermas as outras não. Além disso, por que usar uma correspondência de padrão para o mapa - basta usar mapValues. Então, junte tudo e você terá def woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size)- tente isso e verifique o desempenho para várias listas de tamanhos. Finalmente, nas outras soluções, por que a) declarar mapeb) torná-lo uma var ?? Basta fazerw.foldLeft(Map.empty[Char, Int])...
samthebest
1
Obrigado por fornecer mais dados (mudou meu voto :). Acho que a razão pela qual a implementação de groupBy usa um mapa mutável de Builders que são otimizados para incrementos iterativos. Em seguida, ele converte o mapa mutável em um imutável usando um MapBuilder. Provavelmente, há alguma avaliação preguiçosa acontecendo nos bastidores também para tornar as coisas mais rápidas.
samthebest
@samthebest Basta pesquisar o contador e incrementá-lo. Não vejo o que pode ser armazenado em cache lá. O cache precisa ser um mapa do mesmo tipo de qualquer maneira.
Val
Não estou dizendo que armazena nada em cache. Imagino que o aumento de desempenho venha do uso de Builders e, possivelmente, de alguma avaliação preguiçosa.
samthebest
@samthebest avaliação preguiçosa = avaliação atrasada (chamada por nome) + cache. Você não pode falar sobre avaliação preguiçosa, mas não sobre cache.
Val
4
Não obtive o tamanho da lista usando, lengthmas sim sizecomo uma das respostas acima sugeridas devido ao problema relatado aqui .
val list =List("apple","oranges","apple","banana","apple","oranges","oranges")
list.groupBy(x=>x).map(t =>(t._1, t._2.size))
Uau, 4 iterações na sequência original! Mesmo seq.groupBy(identity).mapValues(_.size)só passa duas vezes.
Weapons Grau
Número de iterações pode não importa para uma pequena string como "Alphabet", mas quando se lida com milhões de itens em uma coleção, iterações certamente fazer importa!
WeaponsGrade
2
Tente isso, deve funcionar.
val list =List(1,2,4,2,4,7,3,2,4)
list.count(_==2)
Como isso difere da resposta de xiefei dada sete anos atrás?
jwvh
0
Esta é uma maneira bem fácil de fazer isso.
val data =List("it","was","the","best","of","times","it","was","the","worst","of","times")
data.foldLeft(Map[String,Int]().withDefaultValue(0)){case(acc, letter)=>
acc +(letter ->(1+ acc(letter)))}// => Map(worst -> 1, best -> 1, it -> 2, was -> 2, times -> 2, of -> 2, the -> 2)
Respostas:
Uma versão um pouco mais limpa de uma das outras respostas é:
dando um
Map
com uma contagem para cada item na sequência original:A questão pergunta como encontrar a contagem de um item específico. Com essa abordagem, a solução exigiria o mapeamento do elemento desejado para seu valor de contagem da seguinte maneira:
fonte
groupBy
requer uma função que se aplica aos elementos para saber como agrupá-los. Uma alternativa para agrupar as strings na resposta por suas identidades poderia ser, digamos, agrupar por seu comprimento (groupBy(_.size)
) ou por sua primeira letra (groupBy(_.head)
).coleções scala têm
count
:list.count(_ == 2)
fonte
Tive o mesmo problema de Sharath Prabhal e consegui outra solução (para mim mais clara):
Com como resultado:
fonte
s.groupBy(identity).mapValues(_.size)
dá
Observe que você pode substituir
(i=>i)
pelaidentity
função integrada :fonte
fonte
Começando
Scala 2.13
, o método groupMapReduce faz isso em uma passagem pela lista:Este:
group
s elementos da lista (grupo parte do grupo MapReduce)map
s cada ocorrência de valor agrupado para 1 (parte do mapa do grupo Reduzir Mapa )reduce
s valores dentro de um grupo de valores (_ + _
) somando-os (reduzir parte de groupMap Reduzir ).Esta é uma versão de uma passagem do que pode ser traduzido por:
fonte
Tive o mesmo problema, mas queria contar vários itens de uma vez.
https://gist.github.com/sharathprabhal/6890475
fonte
Stream
e a resposta aceita resultará em seu objetivo de "uma tentativa" mais código mais claro.Se você quiser usá-lo da mesma forma,
list.count(2)
terá que implementá-lo usando uma classe implícita .fonte
Resposta curta:
Resposta longa:
Usando Scalaz , dado.
então, todos estes (da ordem de menos simplificado para mais simplificado)
produção
fonte
É interessante notar que o mapa com valor padrão 0, intencionalmente projetado para este caso, demonstra o pior desempenho (e não tão conciso quanto
groupBy
)produz
É curioso que mais conciso
groupBy
seja mais rápido do que um mapa mutável!fonte
groupBy
solução tem um desempenho,toLower
mas as outras não. Além disso, por que usar uma correspondência de padrão para o mapa - basta usarmapValues
. Então, junte tudo e você terádef woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size)
- tente isso e verifique o desempenho para várias listas de tamanhos. Finalmente, nas outras soluções, por que a) declararmap
eb) torná-lo uma var ?? Basta fazerw.foldLeft(Map.empty[Char, Int])...
Builder
s que são otimizados para incrementos iterativos. Em seguida, ele converte o mapa mutável em um imutável usando umMapBuilder
. Provavelmente, há alguma avaliação preguiçosa acontecendo nos bastidores também para tornar as coisas mais rápidas.Builder
s e, possivelmente, de alguma avaliação preguiçosa.Não obtive o tamanho da lista usando,
length
mas simsize
como uma das respostas acima sugeridas devido ao problema relatado aqui .fonte
Aqui está outra opção:
fonte
fonte
usando gatos
fonte
seq.groupBy(identity).mapValues(_.size)
só passa duas vezes.Tente isso, deve funcionar.
Ele retornará 3
fonte
Esta é uma maneira bem fácil de fazer isso.
fonte