Je ne sais pas s'il existe un moyen approprié d'obtenir la taille d'une liste dans scala, mais pour votre situation, vous pouvez utiliser une séquence.
Qusay Fantazia
Cette question est-elle toujours sans réponse? Demander parce que vous avez peut-être oublié d'en accepter un.
Tobias Kolb
Réponses:
150
Une version un peu plus claire de l'une des autres réponses est:
val s =Seq("apple","oranges","apple","banana","apple","oranges","oranges")
s.groupBy(identity).mapValues(_.size)
donnant un Mapavec un compte pour chaque élément dans la séquence d'origine:
Map(banana ->1, oranges ->3, apple ->3)
La question demande comment trouver le nombre d'un élément spécifique. Avec cette approche, la solution nécessiterait de mapper l'élément souhaité à sa valeur de comptage comme suit:
C'est la fonction d'identité, comme discuté ici . La fonction groupBynécessite une fonction qu'elle applique aux éléments afin de savoir comment les regrouper. Une alternative au regroupement des chaînes dans la réponse par leur identité pourrait être, par exemple, le regroupement par leur longueur ( groupBy(_.size)) ou par leur première lettre ( groupBy(_.head)).
ohruunuruus
2
L'inconvénient est que beaucoup de collections inutiles (car seule la taille est nécessaire) sont créées.
Yann Moisan
Et si je voulais définir une carte d'accumulateur dans cette expression au lieu de créer une nouvelle carte?
Tobias Kolb
128
Les collections scala ont count:list.count(_ == 2)
Une version un peu plus propre ests.groupBy(identity).mapValues(_.size)
ohruunuruus
1
@ohruunuruus cela devrait être une réponse (vs commentaire); j'adorerais voter avec enthousiasme, si c'était le cas (et le sélectionner comme meilleure réponse si j'étais l'OP);
doug
1
@doug un peu nouveau dans SO et n'était pas sûr, mais heureux d'obliger
ohruunuruus
27
list.groupBy(i=>i).mapValues(_.size)
donne
Map[Int,Int]=Map(1->1,2->3,7->1,3->1,4->3)
Notez que vous pouvez remplacer (i=>i)par une identityfonction intégrée:
aime les solutions courtes utilisant des bibliothèques intégrées
Rustam Aliyev
14
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))
Bien, c'est ce que je cherchais, j'ai trouvé triste que même les flux Java (qui ne sont pas bons à certains égards) permettent cela en un seul passage alors que Scala ne le pouvait pas.
Dici
9
J'ai rencontré le même problème, mais je voulais compter plusieurs éléments en une seule fois.
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)
Il est intéressant de noter que la carte avec la valeur par défaut 0, conçue intentionnellement pour ce cas, montre les pires performances (et pas aussi concises que groupBy)
Je me méfie un peu de cette référence car on ne sait pas quelle est la taille des données. La groupBysolution fonctionne toLowermais les autres non. Aussi pourquoi utiliser une correspondance de modèle pour la carte - utilisez simplement mapValues. Alors roulez ensemble et vous obtenez def woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size)- essayez cela et vérifiez les performances pour différentes listes de tailles. Enfin dans les autres solutions, pourquoi a) déclarermap et b) en faire une var ?? Just dow.foldLeft(Map.empty[Char, Int])...
samthebest
1
Merci d'avoir fourni plus de données (changé mon vote :). Je pense que la raison en est que l'implémentation de groupBy utilise une carte mutable de Builders qui sont optimisées pour les incréments itératifs. Il convertit ensuite la carte mutable en un immuable en utilisant un MapBuilder. Il y a probablement aussi une évaluation paresseuse sous le capot pour accélérer les choses.
samthebest
@samthebest Il vous suffit de rechercher le compteur et de l'incrémenter. Je ne vois pas ce qui peut y être mis en cache. Le cache doit de toute façon être une carte du même type.
Val
Je ne dis pas que ça cache quoi que ce soit. J'imagine que l'augmentation des performances provient de l'utilisation de Builders, et peut-être d'une évaluation paresseuse.
samthebest
@samthebest évaluation paresseuse = évaluation retardée (appel par nom) + mise en cache. Vous ne pouvez pas parler d'évaluation paresseuse mais pas de mise en cache.
Val
4
Je n'ai pas obtenu la taille de la liste en utilisant lengthmais plutôtsize tant que réponse ci-dessus suggérée en raison du problème signalé ici .
val list =List("apple","oranges","apple","banana","apple","oranges","oranges")
list.groupBy(x=>x).map(t =>(t._1, t._2.size))
Wow, 4 itérations dans la séquence originale! Même seq.groupBy(identity).mapValues(_.size)ne passe que deux fois.
WeaponsGrade
Nombre d'itérations ne peut pas importer pour une petite chaîne comme « Alphabet », mais en traitant avec des millions d'articles dans une collection, itérations certainement faire affaire!
WeaponsGrade
2
Essayez ceci, cela devrait fonctionner.
val list =List(1,2,4,2,4,7,3,2,4)
list.count(_==2)
En quoi cela diffère-t-il de la réponse de xiefei donnée il y a sept ans?
jwvh le
0
Voici un moyen assez simple de le faire.
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)
Réponses:
Une version un peu plus claire de l'une des autres réponses est:
donnant un
Map
avec un compte pour chaque élément dans la séquence d'origine:La question demande comment trouver le nombre d'un élément spécifique. Avec cette approche, la solution nécessiterait de mapper l'élément souhaité à sa valeur de comptage comme suit:
la source
groupBy
nécessite une fonction qu'elle applique aux éléments afin de savoir comment les regrouper. Une alternative au regroupement des chaînes dans la réponse par leur identité pourrait être, par exemple, le regroupement par leur longueur (groupBy(_.size)
) ou par leur première lettre (groupBy(_.head)
).Les collections scala ont
count
:list.count(_ == 2)
la source
J'ai eu le même problème que Sharath Prabhal, et j'ai eu une autre solution (pour moi plus claire):
Avec comme résultat:
la source
s.groupBy(identity).mapValues(_.size)
donne
Notez que vous pouvez remplacer
(i=>i)
par uneidentity
fonction intégrée:la source
la source
En commençant
Scala 2.13
, la méthode groupMapReduce fait cela en un seul passage dans la liste:Ce:
group
éléments de liste s (partie de groupe du groupe MapReduce)map
s chaque occurrence de valeur groupée à 1 (mapper une partie du groupe Map Réduire)reduce
s valeurs dans un groupe de valeurs (_ + _
) en les additionnant (réduire une partie de groupMap Réduire ).Ceci est une version en un seul passage de ce qui peut être traduit par:
la source
J'ai rencontré le même problème, mais je voulais compter plusieurs éléments en une seule fois.
https://gist.github.com/sharathprabhal/6890475
la source
Stream
et la réponse acceptée vous donnera votre objectif de "one go" plus un code plus clair.Si vous voulez l'utiliser comme
list.count(2)
vous devez l'implémenter en utilisant une classe implicite .la source
Réponse courte:
Longue réponse:
En utilisant Scalaz , donné.
puis tous ceux-ci (dans l'ordre du moins simplifié au plus simplifié)
rendement
la source
Il est intéressant de noter que la carte avec la valeur par défaut 0, conçue intentionnellement pour ce cas, montre les pires performances (et pas aussi concises que
groupBy
)produit
Il est curieux que la plus concise
groupBy
soit plus rapide que la carte même mutable!la source
groupBy
solution fonctionnetoLower
mais les autres non. Aussi pourquoi utiliser une correspondance de modèle pour la carte - utilisez simplementmapValues
. Alors roulez ensemble et vous obtenezdef woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size)
- essayez cela et vérifiez les performances pour différentes listes de tailles. Enfin dans les autres solutions, pourquoi a) déclarermap
et b) en faire une var ?? Just dow.foldLeft(Map.empty[Char, Int])...
Builder
s qui sont optimisées pour les incréments itératifs. Il convertit ensuite la carte mutable en un immuable en utilisant unMapBuilder
. Il y a probablement aussi une évaluation paresseuse sous le capot pour accélérer les choses.Builder
s, et peut-être d'une évaluation paresseuse.Je n'ai pas obtenu la taille de la liste en utilisant
length
mais plutôtsize
tant que réponse ci-dessus suggérée en raison du problème signalé ici .la source
Voici une autre option:
la source
la source
utiliser des chats
la source
seq.groupBy(identity).mapValues(_.size)
ne passe que deux fois.Essayez ceci, cela devrait fonctionner.
Il reviendra 3
la source
Voici un moyen assez simple de le faire.
la source