val list = List(1,2,4,2,4,7,3,2,4)
I want to implement it like this: list.count(2) (returns 3).
A somewhat cleaner version of one of the other answers is:
val s = Seq("apple", "oranges", "apple", "banana", "apple", "oranges", "oranges")
s.groupBy(identity).mapValues(_.size)
giving a Map with a count for each item in the original sequence:
Map(banana -> 1, oranges -> 3, apple -> 3)
The question asks how to find the count of a specific item. With this approach, the solution would require mapping the desired element to its count value as follows:
s.groupBy(identity).mapValues(_.size)("apple")
scala collections do have count: list.count(_ == 2)
I had the same problem as Sharath Prabhal, and I got another (to me clearer) solution :
val s = Seq("apple", "oranges", "apple", "banana", "apple", "oranges", "oranges")
s.groupBy(l => l).map(t => (t._1, t._2.length))
With as result :
Map(banana -> 1, oranges -> 3, apple -> 3)
list.groupBy(i=>i).mapValues(_.size)
gives
Map[Int, Int] = Map(1 -> 1, 2 -> 3, 7 -> 1, 3 -> 1, 4 -> 3)
Note that you can replace (i=>i) with built in identity function:
list.groupBy(identity).mapValues(_.size)
Starting Scala 2.13, the groupMapReduce method does that in one pass through the list:
// 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
This:
groups list elements (group part of groupMapReduce)
maps each grouped value occurrence to 1 (map part of groupMapReduce)
reduces values within a group of values (_ + _) by summing them (reduce part of groupMapReduce).
This is a one-pass version of what can be translated by:
seq.groupBy(identity).mapValues(_.map(_ => 1).reduce(_ + _))
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))
I ran into the same problem but wanted to count multiple items in one go..
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)
https://gist.github.com/sharathprabhal/6890475
If you want to use it like list.count(2) you have to implement it using an Implicit Class.
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
It is interesting to note that the map with default 0 value, intentionally designed for this case demonstrates the worst performance (and not as concise as 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]) {
}
produces
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
It is curious that most concise groupBy is faster than even mutable map!
Short answer:
import scalaz._, Scalaz._
xs.foldMap(x => Map(x -> 1))
Long answer:
Using Scalaz, given.
import scalaz._, Scalaz._
val xs = List('a, 'b, 'c, 'c, 'a, 'a, 'b, 'd)
then all of these (in the order of less simplified to more simplified)
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))
yield
Map('b -> 2, 'a -> 3, 'c -> 2, 'd -> 1)
Try this, should work.
val list = List(1,2,4,2,4,7,3,2,4)
list.count(_==2)
It will return 3
I did not get the size of the list using length but rather size as one the answer above suggested it because of the issue reported here.
val list = List("apple", "oranges", "apple", "banana", "apple", "oranges", "oranges")
list.groupBy(x=>x).map(t => (t._1, t._2.size))
using cats
import cats.implicits._
"Alphabet".toLowerCase().map(c => Map(c -> 1)).toList.combineAll
"Alphabet".toLowerCase().map(c => Map(c -> 1)).toList.foldMap(identity)
Here is another option:
scala> val list = List(1,2,4,2,4,7,3,2,4)
list: List[Int] = List(1, 2, 4, 2, 4, 7, 3, 2, 4)
scala> list.groupBy(x => x) map { case (k,v) => k-> v.length }
res74: scala.collection.immutable.Map[Int,Int] = Map(1 -> 1, 2 -> 3, 7 -> 1, 3 -> 1, 4 -> 3)
scala> val list = List(1,2,4,2,4,7,3,2,4)
list: List[Int] = List(1, 2, 4, 2, 4, 7, 3, 2, 4)
scala> println(list.filter(_ == 2).size)
3
Here is a pretty easy way to do it.
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)
val words = Array("Mary", "had", "a", "little", "lamb", "its"
, "fleece", "was", "white", "as", "snow", "and", "everywhere"
, "that", "Mary", "went", "the", "lamb", "was", "sure", "to", "go")
words.groupBy(_.length)
I'm fairly new the functional programming, so I'm going through some practice exercises. I want to write a function, given a matrix of unique naturals, let's say 5x5, return a collection of unique matrices of a smaller size, say 3x3, where the matrices must be intact, i.e. created from values that are adjacent in the original.
01 02 03 04 05
06 07 08 09 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
Simple. Just slide across, then down, one by one in groups of 3, to get something that looks like:
01 02 03 | 02 03 04 | 03 04 05 | 06 07 08
06 07 08 | 07 08 09 | 08 09 10 | 11 12 13
11 12 13 | 12 13 14 | 13 14 15 | 16 17 18
or, in Scala,
List(List(1, 2, 3), List(6, 7, 8), List(11, 12, 13))
List(List(2, 3, 4), List(7, 8, 9), List(12, 13, 14))
List(List(3, 4, 5), List(8, 9, 10), List(13, 14, 15))
List(List(6, 7, 8), List(11, 12, 13), List(16, 17, 18))
and so on and so on...
So I venture out with Scala (my language of choice because it allows me to evolve from imperative to functional, and I've spent the last few years in Java.
val array2D = "01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25".grouped(3).map(_.trim.toInt).grouped(5)
val sliced = array2D.map(row => row.sliding(3, 1).toList).sliding(3, 1).toList
Now I have a data structure I can work with, but I don't see a functional way. Sure I can traverse each piece of sliced, create a var matrix = new ListBuffer[Seq[Int]]() and imperatively create a bag of those and I'm done.
I want to find a functional, ideally point-free approach using Scala, but I'm stumped. There's got to be a way to zip with 3 or something like that... I've searched the ScalaDocs and can't seem to figure it out.
You got halfway there. In fact, I was having trouble figuring out how to do what you had done already. I broke up your code a bit to make it easier to follow. Also, I made array2D a List, so I could play with the code more easily. :-)
val input = "01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25"
val intArray = (input split " " map (_.toInt) toList)
val array2D = (intArray grouped 5 toList)
val sliced = array2D.map(row => row.sliding(3, 1).toList).sliding(3, 1).toList
Ok, so you have a bunch of lists, each one a bit like this:
List(List(List( 1, 2, 3), List( 2, 3, 4), List( 3, 4, 5)),
List(List( 6, 7, 8), List( 7, 8, 9), List( 8, 9, 10)),
List(List(11, 12, 13), List(12, 13, 14), List(13, 14, 15)))
And you want them like this:
List(List(List(1, 2, 3), List(6, 7, 8), List(11, 12, 13)),
List(List(2, 3, 4), List(7, 8, 9), List(12, 13, 14)),
List(List(3, 4, 5), List(8, 9, 10), List(13, 14, 15)))
Does that feel right to you? Each of the three sublists is a matrix on its own:
List(List(1, 2, 3), List(6, 7, 8), List(11, 12, 13))
is
01 02 03
06 07 08
11 12 13
So, basically, you want to transpose them. The next step, then, is:
val subMatrices = sliced map (_.transpose)
The type of that thing is List[List[List[Seq[Int]]]]. Let's consider that a bit... The 2D matrix is represented by a sequence of a sequence, so List[Seq[Int]] corresponds to a matrix. Let's say:
type Matrix = Seq[Seq[Int]]
val subMatrices: List[List[Matrix]] = sliced map (_.transpose)
But you want one one list of matrices, so you can flatten that:
type Matrix = Seq[Seq[Int]]
val subMatrices: List[Matrix] = (sliced map (_.transpose) flatten)
But, alas, a map plus a flatten is a flatMap:
type Matrix = Seq[Seq[Int]]
val subMatrices: List[Matrix] = sliced flatMap (_.transpose)
Now, you want the unique submatrices. That's simple enough: it's a set.
val uniqueSubMatrices = subMatrices.toSet
Or, if you wish to keep the result as a sequence,
val uniqueSubMatrices = subMatrices.distinct
And that's it. Full code just to illustrate:
type Matrix = Seq[Seq[Int]]
val input = "01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25"
val intArray = (input split " " map (_.toInt) toList)
val array2D: Matrix = (intArray grouped 5 toList)
val sliced: List[List[Matrix]] = (array2D map (row => row sliding 3 toList) sliding 3 toList)
val subMatrices: List[Matrix] = sliced flatMap (_.transpose)
val uniqueSubMatrices: Set[Matrix] = subMatrices.toSet
It could be written as a single expression, but unless you break it up into functions, it's going to be horrible to read. And you'd either have to use the forward pipe (|>, not in the standard library), or add these functions implicitly to the types they act on, or it will be difficult to read anyway.
Edit: Okay, I think I finally understand what you want. I'm going to show a way that works, not a way that is high-performance. (That's generally the mutable Java-like solution, but you already know how to do that.)
First, you really, really ought to do this with your own collections that work in 2D sensibly. Using a bunch of 1D collections to emulate 2D collections is going to lead to unnecessary confusion and complication. Don't do it. Really. It's a bad idea.
But, okay, let's do it anyway.
val big = (1 to 25).grouped(5).map(_.toList).toList
This is the whole matrix that you want. Next,
val smaller = (for (r <- big.sliding(3)) yield r.toList).toList
are the groups of rows that you want. Now, you should have been using a 2D data structure, because you want to do something that doesn't map well onto 1D operations. But:
val small = smaller.map(xss =>
Iterator.iterate(xss.map(_.sliding(3)))(identity).
takeWhile(_.forall(_.hasNext)).
map(_.map(_.next)).
toList
).toList
If you carefully pull this apart, you see that you're creating a bunch of iterators (xss.map(_.sliding(3))) and then iterating through them all in lock step by keeping hold of those same iterators step after step, stopping when at least one of them is empty, and mapping them onto their next values (which is how you walk forward with them).
Now that you've got the matrices you can store them however you want. Personally, I'd flatten the list:
val flattened = small.flatten
You wrote a structure that has the matrices side by side, which you can also do with some effort (again, because creating 2D operations out of 1D operations is not always straightforward):
val sidebyside = flattened.reduceRight((l,r) => (l,r).zipped.map(_ ::: _))
(note reduceRight to make this an O(n) operation instead of O(n^2)--joining to the end of long accumulating lists is a bad idea--but note also that with too many matrices this will probably overflow the stack).