val list = List(1,2,4,2,4,7,3,2,4)
このように実装したい:(list.count(2)
戻り値3)。
val list = List(1,2,4,2,4,7,3,2,4)
このように実装したい:(list.count(2)
戻り値3)。
回答:
他の答えの1つのややわかりやすいバージョンは次のとおりです。
val s = Seq("apple", "oranges", "apple", "banana", "apple", "oranges", "oranges")
s.groupBy(identity).mapValues(_.size)
与えてMap
元のシーケンス内の各アイテムの数と:
Map(banana -> 1, oranges -> 3, apple -> 3)
この質問では、特定のアイテムの数を見つける方法を尋ねます。このアプローチでは、ソリューションは次のように目的の要素をカウント値にマッピングする必要があります。
s.groupBy(identity).mapValues(_.size)("apple")
groupBy
は要素に適用する関数が必要なので、要素をグループ化する方法を認識します。IDで回答の文字列をグループ化する代わりに、たとえば、長さ(groupBy(_.size)
)または最初の文字(groupBy(_.head)
)でグループ化することもできます。
私はSharath Prabhalと同じ問題を抱えていて、別の(より明確な)解決策を得ました
val s = Seq("apple", "oranges", "apple", "banana", "apple", "oranges", "oranges")
s.groupBy(l => l).map(t => (t._1, t._2.length))
結果として:
Map(banana -> 1, oranges -> 3, apple -> 3)
s.groupBy(identity).mapValues(_.size)
list.groupBy(i=>i).mapValues(_.size)
与える
Map[Int, Int] = Map(1 -> 1, 2 -> 3, 7 -> 1, 3 -> 1, 4 -> 3)
(i=>i)
組み込みidentity
関数で置き換えることができることに注意してください:
list.groupBy(identity).mapValues(_.size)
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))
を開始するScala 2.13
と、groupMapReduceメソッドは、リストの1つのパスでそれを実行します。
// val seq = Seq("apple", "oranges", "apple", "banana", "apple", "oranges", "oranges")
seq.groupMapReduce(identity)(_ => 1)(_ + _)
// immutable.Map[String,Int] = Map(banana -> 1, oranges -> 3, apple -> 3)
seq.groupMapReduce(identity)(_ => 1)(_ + _)("apple")
// Int = 3
この:
group
sリスト要素(グループ MapReduceのグループ部分)
map
sグループ化された各値のオカレンスを1に(グループMap Reduceのマップ部分)
reduce
値のグループ内の値(_ + _
)を合計する(groupMap Reduceの一部を減らす)。
これは、次の言語で翻訳できるもののワンパスバージョンです。
seq.groupBy(identity).mapValues(_.map(_ => 1).reduce(_ + _))
私は同じ問題に遭遇しましたが、一度に複数のアイテムを数えたかったのです。
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)
Stream
して受け入れられた答えは、「1回だけ」という目標に加えて、より明確なコードをもたらすでしょう。
Implicit Classlist.count(2)
を使用して実装する必要があるように使用したい場合。
implicit class Count[T](list: List[T]) {
def count(n: T): Int = list.count(_ == n)
}
List(1,2,4,2,4,7,3,2,4).count(2) // returns 3
List(1,2,4,2,4,7,3,2,4).count(5) // returns 0
短い答え:
import scalaz._, Scalaz._
xs.foldMap(x => Map(x -> 1))
長い答え:
与えられたScalazを使用します。
import scalaz._, Scalaz._
val xs = List('a, 'b, 'c, 'c, 'a, 'a, 'b, 'd)
次に、これらすべて(簡略化されていないものから簡略化されたものの順)
xs.map(x => Map(x -> 1)).foldMap(identity)
xs.map(x => Map(x -> 1)).foldMap()
xs.map(x => Map(x -> 1)).suml
xs.map(_ -> 1).foldMap(Map(_))
xs.foldMap(x => Map(x -> 1))
産出
Map('b -> 2, 'a -> 3, 'c -> 2, 'd -> 1)
このケースのために意図的に設計されたデフォルト値0のマップは、最悪のパフォーマンスを示します(そして、ほど簡潔ではありませんgroupBy
)。
type Word = String
type Sentence = Seq[Word]
type Occurrences = scala.collection.Map[Char, Int]
def woGrouped(w: Word): Occurrences = {
w.groupBy(c => c).map({case (c, list) => (c -> list.length)})
} //> woGrouped: (w: forcomp.threadBug.Word)forcomp.threadBug.Occurrences
def woGetElse0Map(w: Word): Occurrences = {
val map = Map[Char, Int]()
w.foldLeft(map)((m, c) => m + (c -> (m.getOrElse(c, 0) + 1)) )
} //> woGetElse0Map: (w: forcomp.threadBug.Word)forcomp.threadBug.Occurrences
def woDeflt0Map(w: Word): Occurrences = {
val map = Map[Char, Int]().withDefaultValue(0)
w.foldLeft(map)((m, c) => m + (c -> (m(c) + 1)) )
} //> woDeflt0Map: (w: forcomp.threadBug.Word)forcomp.threadBug.Occurrences
def dfltHashMap(w: Word): Occurrences = {
val map = scala.collection.immutable.HashMap[Char, Int]().withDefaultValue(0)
w.foldLeft(map)((m, c) => m + (c -> (m(c) + 1)) )
} //> dfltHashMap: (w: forcomp.threadBug.Word)forcomp.threadBug.Occurrences
def mmDef(w: Word): Occurrences = {
val map = scala.collection.mutable.Map[Char, Int]().withDefaultValue(0)
w.foldLeft(map)((m, c) => m += (c -> (m(c) + 1)) )
} //> mmDef: (w: forcomp.threadBug.Word)forcomp.threadBug.Occurrences
val functions = List("grp" -> woGrouped _, "mtbl" -> mmDef _, "else" -> woGetElse0Map _
, "dfl0" -> woDeflt0Map _, "hash" -> dfltHashMap _
) //> functions : List[(String, String => scala.collection.Map[Char,Int])] = Lis
//| t((grp,<function1>), (mtbl,<function1>), (else,<function1>), (dfl0,<functio
//| n1>), (hash,<function1>))
val len = 100 * 1000 //> len : Int = 100000
def test(len: Int) {
val data: String = scala.util.Random.alphanumeric.take(len).toList.mkString
val firstResult = functions.head._2(data)
def run(f: Word => Occurrences): Int = {
val time1 = System.currentTimeMillis()
val result= f(data)
val time2 = (System.currentTimeMillis() - time1)
assert(result.toSet == firstResult.toSet)
time2.toInt
}
def log(results: Seq[Int]) = {
((functions zip results) map {case ((title, _), r) => title + " " + r} mkString " , ")
}
var groupResults = List.fill(functions.length)(1)
val integrals = for (i <- (1 to 10)) yield {
val results = functions map (f => (1 to 33).foldLeft(0) ((acc,_) => run(f._2)))
println (log (results))
groupResults = (results zip groupResults) map {case (r, gr) => r + gr}
log(groupResults).toUpperCase
}
integrals foreach println
} //> test: (len: Int)Unit
test(len)
test(len * 2)
// GRP 14 , mtbl 11 , else 31 , dfl0 36 , hash 34
// GRP 91 , MTBL 111
println("Done")
def main(args: Array[String]) {
}
作り出す
grp 5 , mtbl 5 , else 13 , dfl0 17 , hash 17
grp 3 , mtbl 6 , else 14 , dfl0 16 , hash 16
grp 3 , mtbl 6 , else 13 , dfl0 17 , hash 15
grp 4 , mtbl 5 , else 13 , dfl0 15 , hash 16
grp 23 , mtbl 6 , else 14 , dfl0 15 , hash 16
grp 5 , mtbl 5 , else 13 , dfl0 16 , hash 17
grp 4 , mtbl 6 , else 13 , dfl0 16 , hash 16
grp 4 , mtbl 6 , else 13 , dfl0 17 , hash 15
grp 3 , mtbl 5 , else 14 , dfl0 16 , hash 16
grp 3 , mtbl 6 , else 14 , dfl0 16 , hash 16
GRP 5 , MTBL 5 , ELSE 13 , DFL0 17 , HASH 17
GRP 8 , MTBL 11 , ELSE 27 , DFL0 33 , HASH 33
GRP 11 , MTBL 17 , ELSE 40 , DFL0 50 , HASH 48
GRP 15 , MTBL 22 , ELSE 53 , DFL0 65 , HASH 64
GRP 38 , MTBL 28 , ELSE 67 , DFL0 80 , HASH 80
GRP 43 , MTBL 33 , ELSE 80 , DFL0 96 , HASH 97
GRP 47 , MTBL 39 , ELSE 93 , DFL0 112 , HASH 113
GRP 51 , MTBL 45 , ELSE 106 , DFL0 129 , HASH 128
GRP 54 , MTBL 50 , ELSE 120 , DFL0 145 , HASH 144
GRP 57 , MTBL 56 , ELSE 134 , DFL0 161 , HASH 160
grp 7 , mtbl 11 , else 28 , dfl0 31 , hash 31
grp 7 , mtbl 10 , else 28 , dfl0 32 , hash 31
grp 7 , mtbl 11 , else 28 , dfl0 31 , hash 32
grp 7 , mtbl 11 , else 28 , dfl0 31 , hash 33
grp 7 , mtbl 11 , else 28 , dfl0 32 , hash 31
grp 8 , mtbl 11 , else 28 , dfl0 31 , hash 33
grp 8 , mtbl 11 , else 29 , dfl0 38 , hash 35
grp 7 , mtbl 11 , else 28 , dfl0 32 , hash 33
grp 8 , mtbl 11 , else 32 , dfl0 35 , hash 41
grp 7 , mtbl 13 , else 28 , dfl0 33 , hash 35
GRP 7 , MTBL 11 , ELSE 28 , DFL0 31 , HASH 31
GRP 14 , MTBL 21 , ELSE 56 , DFL0 63 , HASH 62
GRP 21 , MTBL 32 , ELSE 84 , DFL0 94 , HASH 94
GRP 28 , MTBL 43 , ELSE 112 , DFL0 125 , HASH 127
GRP 35 , MTBL 54 , ELSE 140 , DFL0 157 , HASH 158
GRP 43 , MTBL 65 , ELSE 168 , DFL0 188 , HASH 191
GRP 51 , MTBL 76 , ELSE 197 , DFL0 226 , HASH 226
GRP 58 , MTBL 87 , ELSE 225 , DFL0 258 , HASH 259
GRP 66 , MTBL 98 , ELSE 257 , DFL0 293 , HASH 300
GRP 73 , MTBL 111 , ELSE 285 , DFL0 326 , HASH 335
Done
ほとんどの簡潔なものgroupBy
は変更可能なマップよりも高速であることは興味深いです!
groupBy
解決策を実行しtoLower
ますが、他にはありません。また、マップにパターンマッチを使用する理由-使用してくださいmapValues
。だから一緒にそれを転がして、あなたは得るdef woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size)
-それを試して、さまざまなサイズのリストのパフォーマンスをチェックしてください 最後に、他のソリューションでは、なぜa)宣言しmap
、b)varにするのですか?ただやるw.foldLeft(Map.empty[Char, Int])...
Builder
、反復インクリメントに最適化されたsの可変マップを使用するのはなぜかと思います。次に、を使用して、可変マップを不変マップに変換しMapBuilder
ます。おそらく、物事をより速くするために、内部でも遅延評価が行われているでしょう。
Builder
s の使用、そしておそらく遅延評価によってもたらされると思います。
猫を使う
import cats.implicits._
"Alphabet".toLowerCase().map(c => Map(c -> 1)).toList.combineAll
"Alphabet".toLowerCase().map(c => Map(c -> 1)).toList.foldMap(identity)
seq.groupBy(identity).mapValues(_.size)
二回しか通過します。
これを試して、うまくいくはずです。
val list = List(1,2,4,2,4,7,3,2,4)
list.count(_==2)
3を返します
これを行うのはかなり簡単な方法です。
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)