No sé si existe una forma adecuada de obtener el tamaño de una lista en scala, pero para su situación, podría usar una secuencia.
Qusay Fantazia
¿Sigue esta pregunta sin respuesta? Preguntando porque es posible que se haya olvidado de aceptar uno.
Tobias Kolb
Respuestas:
150
Una versión algo más limpia de una de las otras respuestas es:
val s =Seq("apple","oranges","apple","banana","apple","oranges","oranges")
s.groupBy(identity).mapValues(_.size)
dando un Mapcon un recuento para cada elemento en la secuencia original:
Map(banana ->1, oranges ->3, apple ->3)
La pregunta pregunta cómo encontrar el recuento de un artículo específico. Con este enfoque, la solución requeriría mapear el elemento deseado a su valor de conteo de la siguiente manera:
Es la función de identidad, como se analiza aquí . La función groupByrequiere una función que aplique a elementos para que sepa cómo agruparlos. Una alternativa a agrupar las cadenas en la respuesta por sus identidades podría ser, por ejemplo, agrupar por su longitud ( groupBy(_.size)) o por su primera letra ( groupBy(_.head)).
ohruunuruus
2
El inconveniente es que se crean muchas colecciones inútiles (porque solo se necesita el tamaño).
Yann Moisan
¿Qué pasa si quisiera definir un mapa acumulador en esa expresión en lugar de crear un nuevo mapa?
Tobias Kolb
128
Las colecciones de Scala tienen count:list.count(_ == 2)
Una versión algo más limpia ess.groupBy(identity).mapValues(_.size)
ohruunuruus
1
@ohruunuruus esto debería ser una respuesta (vs comentario); Me encantaría votar con entusiasmo, si lo fuera (y seleccionarla como la mejor respuesta si yo fuera el OP);
doug
1
@doug algo nuevo en SO y no estaba seguro, pero feliz de complacer
ohruunuruus
27
list.groupBy(i=>i).mapValues(_.size)
da
Map[Int,Int]=Map(1->1,2->3,7->1,3->1,4->3)
Tenga en cuenta que puede reemplazar (i=>i)con la identityfunción incorporada:
Me encantan las soluciones breves que utilizan bibliotecas integradas
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, esto es lo que estaba buscando, me pareció triste que incluso los flujos de Java (que no son buenos en algunos aspectos) permitan esto en una sola pasada, mientras que Scala no pudo.
Dici
9
Me encontré con el mismo problema, pero quería contar varios elementos de una 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)
Es interesante notar que el mapa con el valor 0 predeterminado, diseñado intencionalmente para este caso, demuestra el peor desempeño (y no tan conciso como groupBy)
Sospecho un poco de este punto de referencia, ya que no está claro cuál es el tamaño de los datos. La groupBysolución realiza una toLowerpero las otras no. También por qué utilizar una coincidencia de patrón para el mapa - uso justo mapValues. Así que junte eso y obtendrá def woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size): pruébelo y verifique el rendimiento para listas de varios tamaños. Finalmente en las otras soluciones, ¿por qué a) declarar mapyb) convertirlo en var ?? Solo hazlow.foldLeft(Map.empty[Char, Int])...
samthebest
1
Gracias por proporcionar más datos (cambió mi voto :). Creo que la razón por la que la implementación de groupBy usa un mapa mutable de Builders que están optimizados para incrementos iterativos. Luego convierte el mapa mutable en uno inmutable usando un MapBuilder. Probablemente también haya alguna evaluación perezosa bajo el capó para hacer las cosas más rápidas.
samthebest
@samthebest Simplemente busca el contador e incrementalo. No veo qué se puede almacenar en caché allí. El caché debe ser un mapa del mismo tipo de todos modos.
Val
No digo que almacene nada. Imagino que el aumento de rendimiento proviene del uso de Builders, y posiblemente de alguna evaluación perezosa.
samthebest
@samthebest evaluación perezosa = evaluación retrasada (llamada por nombre) + almacenamiento en caché. No se puede hablar de evaluación perezosa pero no de almacenamiento en caché.
Val
4
No obtuve el tamaño de la lista usando, lengthsino más bien, sizecomo una de las respuestas anteriores, lo sugirió debido al problema que se informa aquí .
val list =List("apple","oranges","apple","banana","apple","oranges","oranges")
list.groupBy(x=>x).map(t =>(t._1, t._2.size))
¡Vaya, 4 iteraciones a través de la secuencia original! Incluso seq.groupBy(identity).mapValues(_.size)solo pasa dos veces.
WeaponsGrade
El número de iteraciones puede no importar para una cadena pequeña como "Alfabeto", pero cuando se trata de millones de elementos en una colección, ¡las iteraciones ciertamente sí importan!
WeaponsGrade
2
Prueba esto, debería funcionar.
val list =List(1,2,4,2,4,7,3,2,4)
list.count(_==2)
¿En qué se diferencia esto de la respuesta de xiefei dada hace siete años?
jwvh
0
Aquí tienes una forma bastante sencilla de hacerlo.
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)
Respuestas:
Una versión algo más limpia de una de las otras respuestas es:
dando un
Map
con un recuento para cada elemento en la secuencia original:La pregunta pregunta cómo encontrar el recuento de un artículo específico. Con este enfoque, la solución requeriría mapear el elemento deseado a su valor de conteo de la siguiente manera:
fuente
groupBy
requiere una función que aplique a elementos para que sepa cómo agruparlos. Una alternativa a agrupar las cadenas en la respuesta por sus identidades podría ser, por ejemplo, agrupar por su longitud (groupBy(_.size)
) o por su primera letra (groupBy(_.head)
).Las colecciones de Scala tienen
count
:list.count(_ == 2)
fuente
Tuve el mismo problema que Sharath Prabhal y obtuve otra solución (para mí más clara):
Con como resultado:
fuente
s.groupBy(identity).mapValues(_.size)
da
Tenga en cuenta que puede reemplazar
(i=>i)
con laidentity
función incorporada:fuente
fuente
Comenzando
Scala 2.13
, el método groupMapReduce lo hace en una pasada a través de la lista:Esta:
group
s elementos de lista (grupo parte del grupo MapReduce)map
s cada ocurrencia de valor agrupado a 1 (parte del mapa del grupo Reducción del mapa )reduce
s valores dentro de un grupo de valores (_ + _
) sumándolos (reducir parte de groupMap Reducir ).Esta es una versión de un solo paso de lo que se puede traducir por:
fuente
Me encontré con el mismo problema, pero quería contar varios elementos de una vez.
https://gist.github.com/sharathprabhal/6890475
fuente
Stream
y la respuesta aceptada le dará su objetivo de "una vez" más un código más claro.Si quieres usarlo como
list.count(2)
tienes que implementarlo usando una clase implícita .fuente
Respuesta corta:
Respuesta larga:
Usando Scalaz , dado.
luego todos estos (en el orden de menos simplificado a más simplificado)
rendimiento
fuente
Es interesante notar que el mapa con el valor 0 predeterminado, diseñado intencionalmente para este caso, demuestra el peor desempeño (y no tan conciso como
groupBy
)produce
¡Es curioso que lo más conciso
groupBy
sea más rápido que incluso un mapa mutable!fuente
groupBy
solución realiza unatoLower
pero las otras no. También por qué utilizar una coincidencia de patrón para el mapa - uso justomapValues
. Así que junte eso y obtendrádef woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size)
: pruébelo y verifique el rendimiento para listas de varios tamaños. Finalmente en las otras soluciones, ¿por qué a) declararmap
yb) convertirlo en var ?? Solo hazlow.foldLeft(Map.empty[Char, Int])...
Builder
s que están optimizados para incrementos iterativos. Luego convierte el mapa mutable en uno inmutable usando unMapBuilder
. Probablemente también haya alguna evaluación perezosa bajo el capó para hacer las cosas más rápidas.Builder
s, y posiblemente de alguna evaluación perezosa.No obtuve el tamaño de la lista usando,
length
sino más bien,size
como una de las respuestas anteriores, lo sugirió debido al problema que se informa aquí .fuente
Aquí tienes otra opción:
fuente
fuente
usando gatos
fuente
seq.groupBy(identity).mapValues(_.size)
solo pasa dos veces.Prueba esto, debería funcionar.
Regresará 3
fuente
Aquí tienes una forma bastante sencilla de hacerlo.
fuente