Algorithman
Algorithman

Reputation: 1334

Scala -- List into List of Count and List of Element

Let's say I have Scala list like this:

val mylist = List(4,2,5,6,4,4,2,6,5,6,6,2,5,4,4)

How can I transform it into list of count and list of element? For example, I want to convert mylist into:

val count = List(3,5,3,4)
val elements = List(2,4,5,6)

Which means, in mylist, I have three occurrences of 2, five occurrences of 4, etc.

In procedural, this is easy as I can just make two empty lists (for count and elements) and fill them while doing iteration. However, I have no idea on how to achieve this in Scala.

Upvotes: 0

Views: 3230

Answers (4)

Prashant
Prashant

Reputation: 13

You can try like this as well alternative way of doing the same.

Step - 1

scala> val mylist = List(4,2,5,6,4,4,2,6,5,6,6,2,5,4,4)

mylist: List[Int] = List(4, 2, 5, 6, 4, 4, 2, 6, 5, 6, 6, 2, 5, 4, 4)

// Use groupBy { x => x } returns a "Map[Int, List[Int]]"

step - 2

scala> mylist.groupBy(x => (x))

res0: scala.collection.immutable.Map[Int,List[Int]] = Map(2 -> List(2, 2, 2), 5 -> List(5, 5, 5), 4 -> List(4, 4, 4, 4, 4), 6 -> List(6, 6, 6, 6))

step - 3

scala> mylist.groupBy(x => (x)).map{case(num,times) =>(num,times.size)}.toList

res1: List[(Int, Int)] = List((2,3), (5,3), (4,5), (6,4))

step -4 - sort by num

scala> mylist.groupBy(x => (x)).map{case(num,times) =>(num,times.size)}.toList.sortBy(_._1)

res2: List[(Int, Int)] = List((2,3), (4,5), (5,3), (6,4))

step -5 - unzip to beak into to list it return tuple

scala> mylist.groupBy(x => (x)).map{case(num,times) =>(num,times.size)}.toList.sortBy(_._1).unzip res3: (List[Int], List[Int]) = (List(2, 4, 5, 6),List(3, 5, 3, 4))

Upvotes: 0

igorpcholkin
igorpcholkin

Reputation: 967

Arguably a shortest version:

 val elements = mylist.distinct
 val count = elements map (e => mylist.count(_ == e))

Upvotes: 6

Marth
Marth

Reputation: 24832

Use .groupBy(identity) to create a Map regrouping elements with their occurences:

scala> val mylist = List(4,2,5,6,4,4,2,6,5,6,6,2,5,4,4)
mylist: List[Int] = List(4, 2, 5, 6, 4, 4, 2, 6, 5, 6, 6, 2, 5, 4, 4)

scala> mylist.groupBy(identity)
res0: scala.collection.immutable.Map[Int,List[Int]] = Map(2 -> List(2, 2, 2), 5 -> List(5, 5, 5), 4 -> List(4, 4, 4, 4, 4), 6 -> List(6, 6, 6, 6))

Then you can use .mapValues(_.length) to change the 'value' part of the map to the size of the list:

scala> mylist.groupBy(identity).mapValues(_.length)
res1: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3, 5 -> 3, 4 -> 5, 6 -> 4)

If you want to get 2 lists out of this you can use .unzip, which returns a tuple, the first part being the keys (ie the elements), the second being the values (ie the number of instances of the element in the original list):

scala> val (elements, counts) = mylist.groupBy(identity).mapValues(_.length).unzip
elements: scala.collection.immutable.Iterable[Int] = List(2, 5, 4, 6)
counts: scala.collection.immutable.Iterable[Int] = List(3, 3, 5, 4)

Upvotes: 4

Tzach Zohar
Tzach Zohar

Reputation: 37852

One way would be to use groupBy and then check the size of each "group":

val withSizes = mylist.groupBy(identity).toList.map { case (v, l) => (v, l.size) }
val count = withSizes.map(_._2)
val elements = withSizes.map(_._1)

Upvotes: 2

Related Questions