Scala grouping list into list tuples with one shared element - scala

What would be short functional way to split list
List(1, 2, 3, 4, 5) into List((1,2), (2, 3), (3, 4), (4, 5))

(assuming you don't care if you nested pairs are Lists and not Tuples)
Scala collections have a sliding window function:
# val lazyWindow = List(1, 2, 3, 4, 5).sliding(2)
lazyWindow: Iterator[List[Int]] = non-empty iterator
To realize the collection:
# lazyWindow.toList
res1: List[List[Int]] = List(List(1, 2), List(2, 3), List(3, 4), List(4, 5))
You can even do more "funcy" windows, like of length 3 but with step 2:
# List(1, 2, 3, 4, 5).sliding(3,2).toList
res2: List[List[Int]] = List(List(1, 2, 3), List(3, 4, 5))

You can zip the list with its tail:
val list = List(1, 2, 3, 4, 5)
// list: List[Int] = List(1, 2, 3, 4, 5)
list zip list.tail
// res6: List[(Int, Int)] = List((1,2), (2,3), (3,4), (4,5))

I have always been a big fan of pattern matching. So you could also do:
val list = List(1, 2, 3, 4, 5, 6)
def splitList(list: List[Int], result: List[(Int, Int)] = List()): List[(Int, Int)] = {
list match {
case Nil => result
case x :: Nil => result
case x1 :: x2 :: ls => splitList(x2 :: ls, result.:+(x1, x2))
}
}
splitList(list)
//List((1,2), (2,3), (3,4), (4,5), (5,6))

Related

Scala .init method example

Can you please explain what init method performs with respect to below list
i can see the result of new list says that last sequence is being omitted from the existing list.
val numbers = List(1, 2, 3, 4, 5)
val result = numbers.init
println(result)
.init and .last are the compliments to the .head and .tail methods.
val nums = List(1,2,3,4)
nums.head //res0: Int = 1
nums.tail //res1: List[Int] = List(2, 3, 4)
nums.init //res2: List[Int] = List(1, 2, 3)
nums.last //res3: Int = 4
def init: List[A] which selects all elements except the last.
l: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)
scala> l.last
res58: Int = 8
scala> l.init
res59: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
scala> val testList = List(1,2,3,4,5)
testList: List[Int] = List(1, 2, 3, 4, 5)
scala> testList.init
res0: List[Int] = List(1, 2, 3, 4)
scala> testList.last
res1: Int = 5
scala> testList.head
res2: Int = 1
scala> testList.tail
res3: List[Int] = List(2, 3, 4, 5)

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.
Arguably a shortest version:
val elements = mylist.distinct
val count = elements map (e => mylist.count(_ == e))
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)
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)
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))

Remove one element from Scala List

For example, if I have a list of List(1,2,1,3,2), and I want to remove only one 1, so the I get List(2,1,3,2). If the other 1 was removed it would be fine.
My solution is:
scala> val myList = List(1,2,1,3,2)
myList: List[Int] = List(1, 2, 1, 3, 2)
scala> myList.patch(myList.indexOf(1), List(), 1)
res7: List[Int] = List(2, 1, 3, 2)
But I feel like I am missing a simpler solution, if so what am I missing?
surely not simpler:
def rm(xs: List[Int], value: Int): List[Int] = xs match {
case `value` :: tail => tail
case x :: tail => x :: rm(tail, value)
case _ => Nil
}
use:
scala> val xs = List(1, 2, 1, 3)
xs: List[Int] = List(1, 2, 1, 3)
scala> rm(xs, 1)
res21: List[Int] = List(2, 1, 3)
scala> rm(rm(xs, 1), 1)
res22: List[Int] = List(2, 3)
scala> rm(xs, 2)
res23: List[Int] = List(1, 1, 3)
scala> rm(xs, 3)
res24: List[Int] = List(1, 2, 1)
you can zipWithIndex and filter out the index you want to drop.
scala> val myList = List(1,2,1,3,2)
myList: List[Int] = List(1, 2, 1, 3, 2)
scala> myList.zipWithIndex.filter(_._2 != 0).map(_._1)
res1: List[Int] = List(2, 1, 3, 2)
The filter + map is collect,
scala> myList.zipWithIndex.collect { case (elem, index) if index != 0 => elem }
res2: List[Int] = List(2, 1, 3, 2)
To remove first occurrence of elem, you can split at first occurance, drop the element and merge back.
list.span(_ != 1) match { case (before, atAndAfter) => before ::: atAndAfter.drop(1) }
Following is expanded answer,
val list = List(1, 2, 1, 3, 2)
//split AT first occurance
val elementToRemove = 1
val (beforeFirstOccurance, atAndAfterFirstOccurance) = list.span(_ != elementToRemove)
beforeFirstOccurance ::: atAndAfterFirstOccurance.drop(1) // shouldBe List(2, 1, 3, 2)
Resource
How to remove an item from a list in Scala having only its index?
How should I remove the first occurrence of an object from a list in Scala?
List is immutable, so you can’t delete elements from it, but you can filter out the elements you don’t want while you assign the result to a new variable:
scala> val originalList = List(5, 1, 4, 3, 2)
originalList: List[Int] = List(5, 1, 4, 3, 2)
scala> val newList = originalList.filter(_ > 2)
newList: List[Int] = List(5, 4, 3)
Rather than continually assigning the result of operations like this to a new variable, you can declare your variable as a var and reassign the result of the operation back to itself:
scala> var x = List(5, 1, 4, 3, 2)
x: List[Int] = List(5, 1, 4, 3, 2)
scala> x = x.filter(_ > 2)
x: List[Int] = List(5, 4, 3)

What is Scalas Product.productIterator supposed to do?

Can someone tell me why I am getting different results when using Tuple2[List,List] and List[List] as my Product in the code below? Specifically I would like to know why the second value of the list of lists gets wrapped in another list?
scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)
scala> val b = List(4,5,6)
b: List[Int] = List(4, 5, 6)
scala> val c = List(a,b)
c: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6))
scala> c.productIterator.foreach( println(_) )
List(1, 2, 3)
List(List(4, 5, 6)) // <-- Note this
scala> val d = (a,b)
d: (List[Int], List[Int]) = (List(1, 2, 3),List(4, 5, 6))
scala> d.productIterator.foreach( println(_) )
List(1, 2, 3)
List(4, 5, 6) // <-- Compared to this
(I have read the (absolutely minimal) description of Scala's Product and the productIterator method on http://www.scala-lang.org/api/current/index.html#scala.Product )
Basically, Tuple means a product between all of its elements, but a non-empty List is a product between its head and tail.
This happens for List, because all case classes extend Product, and represent a product between all their elements similar to tuples. And non-empty List is defined as a case class, containing head and tail: final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B], which inherits the default implementation of Product by case class.
You can observe more of this behaviour with other Lists with 1 or more than 2 elements:
scala> List(a).productIterator.foreach(println)
List(1, 2, 3)
List()
scala> List(a, a).productIterator.foreach(println)
List(1, 2, 3)
List(List(1, 2, 3))
scala> List(a, a, a).productIterator.foreach(println)
List(1, 2, 3)
List(List(1, 2, 3), List(1, 2, 3))

All possible permutations of values for such a map

Consider such a map:
Map("one" -> Iterable(1,2,3,4), "two" -> Iterable(3,4,5), "three" -> Iterable(1,2))
I want to get a list of all possible permutations of elements under Iterable, one element for each key. For this example, this would be something like:
// first element of "one", first element of "two", first element of "three"
// second element of "one", second element of "two", second element of "three"
// third element of "one", third element of "two", first element of "three"
// etc.
Seq(Iterable(1,3,1), Iterable(2,4,2), Iterable(3,5,1),...)
What would be a good way to accomplish that?
val m = Map("one" -> Iterable(1,2,3,4), "two" -> Iterable(5,6,7), "three" -> Iterable(8,9))
If you want every combination:
for (a <- m("one"); b <- m("two"); c <- m("three")) yield Iterable(a,b,c)
If you want each iterable to march up together, but stop when the shortest is exhuasted:
(m("one"), m("two"), m("three")).zipped.map((a,b,c) => Iterable(a,b,c))
If you want each iterable to wrap around but stop when the longest one has been exhausted:
val maxlen = m.values.map(_.size).max
def icf[A](i: Iterable[A]) = Iterator.continually(i).flatMap(identity).take(maxlen).toList
(icf(m("one")), icf(m("two")), icf(m("three"))).zipped.map((a,b,c) => Iterable(a,b,c))
Edit: If you want arbitrary numbers of input lists, then you're best off with recursive functions. For Cartesian products:
def cart[A](iia: Iterable[Iterable[A]]): List[List[A]] = {
if (iia.isEmpty) List()
else {
val h = iia.head
val t = iia.tail
if (t.isEmpty) h.map(a => List(a)).toList
else h.toList.map(a => cart(t).map(x => a :: x)).flatten
}
}
and to replace zipped you want something like:
def zipper[A](iia: Iterable[Iterable[A]]): List[List[A]] = {
def zipp(iia: Iterable[Iterator[A]], part: List[List[A]] = Nil): List[List[A]] = {
if (iia.isEmpty || !iia.forall(_.hasNext)) part
else zipp(iia, iia.map(_.next).toList :: part)
}
zipp(iia.map(_.iterator))
}
You can try these out with cart(m.values), zipper(m.values), and zipper(m.values.map(icf)).
If you are out for an cartesian product, I have a solution for lists of lists of something.
xproduct (List (List (1, 2, 3, 4), List (3, 4, 5), List (1, 2)))
res3: List[List[_]] = List(List(1, 3, 1), List(2, 3, 1), List(3, 3, 1), List(4, 3, 1), List(1, 3, 2), List(2, 3, 2), List(3, 3, 2), List(4, 3, 2), List(1, 4, 1), List(2, 4, 1), List(3, 4, 1), List(4, 4, 1), List(1, 4, 2), List(2, 4, 2), List(3, 4, 2), List(4, 4, 2), List(1, 5, 1), List(2, 5, 1), List(3, 5, 1), List(4, 5, 1), List(1, 5, 2), List(2, 5, 2), List(3, 5, 2), List(4, 5, 2))
Invoke it with Rex' m:
xproduct (List (m("one").toList, m("two").toList, m("three").toList))
Have a look at this answer. The question is about a fixed number of lists to combine, but some answers address the general case.