Nie wiem, czy istnieje właściwy sposób uzyskania rozmiaru listy w scali, ale w twojej sytuacji możesz użyć sekwencji.
Qusay Fantazia,
Czy to pytanie nadal pozostaje bez odpowiedzi? Pytanie, ponieważ mogłeś zapomnieć o przyjęciu.
Tobias Kolb,
Odpowiedzi:
150
Nieco czystsza wersja jednej z pozostałych odpowiedzi to:
val s =Seq("apple","oranges","apple","banana","apple","oranges","oranges")
s.groupBy(identity).mapValues(_.size)
dając Mapz liczbą dla każdego elementu w oryginalnej sekwencji:
Map(banana ->1, oranges ->3, apple ->3)
Pytanie dotyczy tego, jak znaleźć liczbę określonej pozycji. Przy takim podejściu rozwiązanie wymagałoby odwzorowania żądanego elementu na jego wartość licznika w następujący sposób:
Jest to funkcja tożsamości, o której tutaj mowa . Funkcja groupBywymaga funkcji, którą stosuje do elementów, aby wiedziała, jak je grupować. Alternatywą dla grupowania ciągów w odpowiedzi według ich tożsamości może być, powiedzmy, grupowanie według ich długości ( groupBy(_.size)) lub pierwszej litery ( groupBy(_.head)).
ohruunuruus
2
Wadą jest to, że powstaje wiele bezużytecznych kolekcji (ponieważ potrzebny jest tylko rozmiar).
Yann Moisan
co jeśli chciałbym zdefiniować mapę akumulatorów w tym wyrażeniu zamiast tworzyć nową mapę?
Nieco czystszą wersją jests.groupBy(identity).mapValues(_.size)
ohruunuruus
1
@ohruunuruus to powinna być odpowiedź (a komentarz); chciałbym entuzjastycznie zagłosować za, gdyby tak było (i wybrałbym to jako najlepszą odpowiedź, gdybym był OP);
Doug
1
@doug nieco nowy w SO i nie był pewien, ale z przyjemnością zobowiązuję się
ohruunuruus
27
list.groupBy(i=>i).mapValues(_.size)
daje
Map[Int,Int]=Map(1->1,2->3,7->1,3->1,4->3)
Pamiętaj, że możesz zastąpić (i=>i)wbudowaną identityfunkcją:
uwielbiam krótkie rozwiązania wykorzystujące wbudowane biblioteki
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))
Fajnie, właśnie tego szukałem, było mi smutno, że nawet strumienie Java (które nie są dobre w niektórych aspektach) pozwalają na to w jednym przebiegu, podczas gdy Scala nie.
Dici
9
Napotkałem ten sam problem, ale chciałem policzyć wiele elementów za jednym razem.
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)
Warto zauważyć, że mapa z domyślną wartością 0, celowo zaprojektowana dla tego przypadku, wykazuje najgorszą wydajność (i nie jest tak zwięzła groupBy)
Jestem trochę podejrzliwy w stosunku do tego testu porównawczego, ponieważ nie jest jasne, jaki jest rozmiar danych. groupByRozwiązanie wykonuje toLowerale inni nie. Po co też używać dopasowania wzorca do mapy - po prostu użyj mapValues. Więc skręć to razem i otrzymaj def woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size)- spróbuj tego i sprawdź wydajność dla różnych list rozmiarów. Wreszcie w innych rozwiązaniach, dlaczego a) deklarować mapib) czynić z var ?? Po prostu zróbw.foldLeft(Map.empty[Char, Int])...
samthebest
1
Dziękuję za podanie większej ilości danych (zmieniłem mój głos :). Myślę, że powodem jest to, że implementacja groupBy wykorzystuje zmienną mapę Builders, która jest zoptymalizowana pod kątem iteracyjnych przyrostów. Następnie konwertuje zmienną mapę na niezmienną przy użyciu MapBuilder. Prawdopodobnie pod maską dzieje się też leniwa ocena, aby przyspieszyć.
samthebest
@samthebest Wystarczy spojrzeć na licznik i zwiększyć go. Nie widzę, co można tam zapisać w pamięci podręcznej. Pamięć podręczna i tak musi być mapą tego samego rodzaju.
Val
Nie mówię, że cokolwiek buforuje. Wyobrażam sobie, że wzrost wydajności wynika z użycia Builders i prawdopodobnie leniwej oceny.
samthebest
@samthebest leniwa ocena = opóźniona ocena (wywołanie według nazwy) + buforowanie. Nie można mówić o leniwej ocenie, ale nie o buforowaniu.
Val
4
Nie otrzymałem rozmiaru listy za pomocą, lengthale raczej sizejako jedna z powyższych odpowiedzi zasugerowała to z powodu zgłoszonego tutaj problemu .
val list =List("apple","oranges","apple","banana","apple","oranges","oranges")
list.groupBy(x=>x).map(t =>(t._1, t._2.size))
Wow, 4 iteracje oryginalnej sekwencji! Nawet seq.groupBy(identity).mapValues(_.size)przechodzi tylko dwa razy.
WeaponsGrade
Liczba iteracji może nie mieć znaczenia w przypadku małego ciągu, takiego jak „Alphabet”, ale w przypadku milionów elementów w kolekcji iteracje z pewnością mają znaczenie!
Klasa broni
2
Spróbuj tego, powinno działać.
val list =List(1,2,4,2,4,7,3,2,4)
list.count(_==2)
Czym różni się to od odpowiedzi udzielonej siedem lat temu przez xiefei?
jwvh
0
Oto całkiem prosty sposób na zrobienie tego.
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)
Odpowiedzi:
Nieco czystsza wersja jednej z pozostałych odpowiedzi to:
dając
Map
z liczbą dla każdego elementu w oryginalnej sekwencji:Pytanie dotyczy tego, jak znaleźć liczbę określonej pozycji. Przy takim podejściu rozwiązanie wymagałoby odwzorowania żądanego elementu na jego wartość licznika w następujący sposób:
źródło
groupBy
wymaga funkcji, którą stosuje do elementów, aby wiedziała, jak je grupować. Alternatywą dla grupowania ciągów w odpowiedzi według ich tożsamości może być, powiedzmy, grupowanie według ich długości (groupBy(_.size)
) lub pierwszej litery (groupBy(_.head)
).kolekcje scala posiadają
count
:list.count(_ == 2)
źródło
Miałem ten sam problem co Sharath Prabhal i dostałem inne (dla mnie jaśniejsze) rozwiązanie:
W rezultacie:
źródło
s.groupBy(identity).mapValues(_.size)
daje
Pamiętaj, że możesz zastąpić
(i=>i)
wbudowanąidentity
funkcją:źródło
źródło
Zaczynając
Scala 2.13
, metoda groupMapReduce robi to w jednym przejściu przez listę:To:
group
Elementy listy s (część grupowa grupy MapReduce)map
s każde wystąpienie wartości zgrupowanej do 1 (część mapy grupy Map Reduce)reduce
s wartości w grupie wartości (_ + _
), sumując je (zmniejsz część groupMap Reduce ).To jest jednoprzebiegowa wersja tego, co można przetłumaczyć za pomocą:
źródło
Napotkałem ten sam problem, ale chciałem policzyć wiele elementów za jednym razem.
https://gist.github.com/sharathprabhal/6890475
źródło
Stream
i zaakceptowana odpowiedź przyniesie cel „jednorazowo” i jaśniejszy kod.Jeśli chcesz go używać, tak jak
list.count(2)
musisz zaimplementować go przy użyciu klasy niejawnej .źródło
Krótka odpowiedź:
Długa odpowiedź:
Używając Scalaz , dane.
to wszystkie te (w kolejności od mniej uproszczonego do bardziej uproszczonego)
wydajność
źródło
Warto zauważyć, że mapa z domyślną wartością 0, celowo zaprojektowana dla tego przypadku, wykazuje najgorszą wydajność (i nie jest tak zwięzła
groupBy
)produkuje
Ciekawe, że najbardziej zwięzłe
groupBy
jest szybsze niż nawet zmienna mapa!źródło
groupBy
Rozwiązanie wykonujetoLower
ale inni nie. Po co też używać dopasowania wzorca do mapy - po prostu użyjmapValues
. Więc skręć to razem i otrzymajdef woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size)
- spróbuj tego i sprawdź wydajność dla różnych list rozmiarów. Wreszcie w innych rozwiązaniach, dlaczego a) deklarowaćmap
ib) czynić z var ?? Po prostu zróbw.foldLeft(Map.empty[Char, Int])...
Builder
s, która jest zoptymalizowana pod kątem iteracyjnych przyrostów. Następnie konwertuje zmienną mapę na niezmienną przy użyciuMapBuilder
. Prawdopodobnie pod maską dzieje się też leniwa ocena, aby przyspieszyć.Builder
s i prawdopodobnie leniwej oceny.Nie otrzymałem rozmiaru listy za pomocą,
length
ale raczejsize
jako jedna z powyższych odpowiedzi zasugerowała to z powodu zgłoszonego tutaj problemu .źródło
Oto inna opcja:
źródło
źródło
za pomocą kotów
źródło
seq.groupBy(identity).mapValues(_.size)
przechodzi tylko dwa razy.Spróbuj tego, powinno działać.
Zwróci 3
źródło
Oto całkiem prosty sposób na zrobienie tego.
źródło