Scala - Combine two lists in an alternating fashion - list

How do I merge 2 lists in such a way that the resulting list contains the elements of 2 lists in alternating fashion in Scala.
Input:
val list1 = List("Mary", "a", "lamb")
val list2 = List("had", "little")
Output:
List("Mary", "had", "a", "little", "lamb")

What you're looking for is usually called "intersperse" or "intercalate" and there are a few ways to do it:
def intersperse[A](a : List[A], b : List[A]): List[A] = a match {
case first :: rest => first :: intersperse(b, rest)
case _ => b
}
You can also use scalaz
import scalaz._
import Scalaz._
val lst1 = ...
val lst2 = ...
lst1 intercalate lst2
Edit: You can also do the following:
lst1.zipAll(lst2,"","") flatMap { case (a, b) => Seq(a, b) }
Come to think of it, I believe the last solution is my favorite since it's most concise while still being clear. If you're already using Scalaz, I'd use the second solution. The first is also very readable however.
And just to make this answer more complete, adding #Travis Brown's solution that is generic:
list1.map(List(_)).zipAll(list2.map(List(_)), Nil, Nil).flatMap(Function.tupled(_ ::: _))

val list1 = List("Mary", "a", "lamb")
val list2 = List("had", "little")
def merge1(list1: List[String], list2: List[String]): List[String] = {
if (list1.isEmpty) list2
else list1.head :: merge(list2, list1.tail)
}
def merge2(list1: List[String], list2: List[String]): List[String] = list1 match {
case List() => list2
case head :: tail => head :: merge(list2, tail)
}
merge1(list1, list2)
merge2(list1, list2)
//> List[String] = List(Mary, had, a, little, lamb)

list1.zipAll(list2,"","").flatMap(_.productIterator.toList).filter(_ != "")

You could do something like this:
def alternate[A]( a: List[A], b: List[A] ): List[A] = {
def first( a: List[A], b: List[A] ): List[A] = a match {
case Nil => Nil
case x :: xs => x :: second( xs, b )
}
def second( a: List[A], b: List[A] ): List[A] = b match {
case Nil => Nil
case y :: ys => y :: first( a, ys )
}
first( a, b )
}

Related

Converting two lists to type : List[List[scala.collection.immutable.Map[String,String]]]

Have two Lists :
val list1 : List[List[(String, String)]] = List(List("1" -> "a" , "1" -> "b"))
//> list1 : List[List[(String, String)]] = List(List((1,a), (1,b)))
val list2 : List[List[(String, String)]] = List(List("2" -> "a" , "2" -> "b"))
//> list2 : List[List[(String, String)]] = List(List((2,a), (2,b)))
//Expecting
val toConvert = List(List(Map("1" -> "a" , "2" -> "b"), Map("1" -> "b" , "2" -> "a")))
Attempting to convert these lists to type :
List[List[scala.collection.immutable.Map[String,String]]] = Lis
//| t(List(Map(1 -> a, 2 -> b), Map(1 -> b, 2 -> a)))
Using this code :
val ll = list1.zip(list2).map(m => List(m._1.toMap , m._2.toMap))
But Map entries are missing :
List[List[scala.collection.immutable.Map[String,String]]] = List(List(
//| Map(1 -> b), Map(2 -> b)))
How to convert list1,list2 to type List[List[scala.collection.immutable.Map[String,String]]] which includes values : (List(Map(1 -> a, 2 -> b), Map(1 -> b, 2 -> a))) ?
Update :
Logic of : Map("1" -> "a" , "2" -> "b")
Combine each List using the zip functions :
val p1 : List[(List[(String, String)], List[(String, String)])] = list1.zip(list2);
Convert each element of thenewly created List to a Map and then add to a newly created List :
val p2 = p1.map(m => List(m._1.toMap , m._2.toMap))
How to convert list1 and list2 to type List[List[Map[...
Starting from the type List[List[(String, String)]] we would like to get to the type List[List[Map[String, String]]].
Inner Type
The inner type we want is Map[String, String]. As I asked in the comments, I don't fully understand the expected logic to construct this Map so I am assuming you want to create a Map[String, String] from a list of tuples List[(String, String)].
When creating the Map using .toMap, the key-value elements with the same key will get overwritten as we can see clearly from the b += x in its implementation:
def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] = {
val b = immutable.Map.newBuilder[T, U]
for (x <- self)
b += x
b.result()
}
(source TraversableOnce.scala)
So the logic we use to create List[(String, String)] will determine the generated Map[String, String].
Outer List of List
Combine each List using the zip functions
type A = List[(String, String)]
val list12: List[(A, A)] = list1 zip list2
Zipping list1 and list2 gives us a list of tuples but the type we want is actually a list of list of tuple: List[List[(A, A)]]
In your example you are getting that type mapping to a list m => List(...). That is the key part. Let me split that in 2 parts to make it clearer:
list12.map(m => List(m._1 , m._2)).map(_.map(_.toMap))
Let's extract that into a separate function:
def keyPart: ((A, A)) => List[A] = { case (l1, l2) => List(l1, l2) }
val resultNotExpected = list12.map(keyPart).map(_.map(_.toMap))
The result is of course the same of the one in your question:
resultNotExpected == List(List(Map("1" -> "b"), Map("2" -> "b")))
The "keyPart"
In your question you mentioned the expected result as:
List(List(Map("1" -> "a", "2" -> "b"), Map("1" -> "b", "2" -> "a")))
I still don't understand the logic you have in mind for the now extracted keyPart function so I would give you mine... over-complex of course:
val resultExpected = list12.map { case (l1, l2) => List(l1, l2) }
.map(_.map(_.zipWithIndex)).map(_.zipWithIndex)
.map(_.map { case (l, i) => l.map { case ((k, v), j) => (k, v, i, j) } }).map(_.flatten)
.map(_.groupBy { case (k, v, i, j) => i == j }).map(_.values.toList)
.map(_.map(_.map { case (k, v, _, _) => k -> v }.sorted).sortBy(_.head._2))
.map(_.map(_.toMap))
scala> resultExpected == List(List(Map("1" -> "a", "2" -> "b"), Map("1" -> "b", "2" -> "a")))
Boolean = true
Perhaps you know better the logic to be implemented in keyPart.

Scala check if List contains slice of element of other List

A : List[String]
B : List[String]
I want to know if any element of List B is a slice of any element of list A.
Whats the fastest way to check it?
I think the shortest way is: ListA.exists{ListB.contains}
Fastest for whom? For you or the CPU?
scala> val a = List("abc","def","ghi") ; val b = List("xy", "yz", "ef")
a: List[String] = List(abc, def, ghi)
b: List[String] = List(xy, yz, ef)
scala> b exists (s => a exists (_ contains s))
res0: Boolean = true
scala> val a = List("abc","def","ghi") ; val b = List("xy", "yz")
a: List[String] = List(abc, def, ghi)
b: List[String] = List(xy, yz)
scala> b exists (s => a exists (_ contains s))
res1: Boolean = false

In a function in won't compile but outside it will

def combinations(list: List[(Char, Int)]) : List[List[(Char,Int)]]= {
val t = List.range(0, 1)
list match {
case List() => List()
case (c,i) :: xs => val res = for {
o <- List.range(1, i + 1)
} yield List((c, o)) :: combinations(xs)
List()
}
}
I have the following function which won't compile if I try to return res instead of List(). It's a type mismatch of List(List(List[(Char,Int)]]] However this code:
List(('a',10)) :: combinations(List())
compiles perfectly and as expected. Why is it that inside the function it won't compile? Isn't it the exact same thing? How could I tackle this?
Your for-comprehension yields an element of type List[List[(Char,Int)]].
For-comprehensions will generate lists of the elements they're yielding, so in this case that will be a List[List[List[(Char,Int)]]].
I'm not entirely sure what you're trying to achieve, but I think it'll be something like this:
def combinations(list: List[(Char, Int)]) : List[List[(Char,Int)]]= {
val t = List.range(0, 1)
list match {
case Nil => List()
case (c,i) :: xs =>
(for {
o <- List.range(1, i + 1)
} yield (c, o)) :: combinations(xs)
}
}
The for-comprehension generates a List[(Char, Int)] which is added at the head of the list generated by your combinations method.

How to extend a Scala list to enable slicing not by explicit position but by given predicate/condition

For
trait Item
case class TypeA(i: Int) extends Item
case class TypeB(i: Int) extends Item
consider a Scala list of items such as
val myList = List(TypeA(1), TypeB(11), TypeB(12),
TypeA(2), TypeB(21),
TypeA(3), TypeB(31))
The goal is to define a new slice method that can be applied onto myList and which takes a predicate or condition as argument; for instance
myList.slice { x => x.isInstanceOf[TypeA] }
would deliver
List(List(TypeA(1), TypeB(11), TypeB(12)),
List(TypeA(2), TypeB(21)),
List(TypeA(3), TypeB(31)))
In this example, an identical result would be achieved by
myList.slice { case TypeA(x) => x < 10 }
Many Thanks.
List already has a slice method - it takes a subset of elements between a start and end index. What you're looking for is repeated application of the span method:
def span(p: (A) ⇒ Boolean): (List[A], List[A])
Which is documented as:
Splits this list into a prefix/suffix pair according to a predicate.
Note: c span p is equivalent to (but possibly more efficient than) (c takeWhile p, c dropWhile p), provided the evaluation of the predicate p does not cause any side-effects.
returns: a pair consisting of the longest prefix of this list whose elements all satisfy p, and the rest of this list.
You can get what you need by repeatedly using this method with an inverse predicate, and an extra bit of logic to ensure that none of the returned Lists are empty.
import annotation.tailrec
def multiSpan[A](xs: List[A])(splitOn: (A) => Boolean): List[List[A]] = {
#tailrec
def loop(xs: List[A], acc: List[List[A]]) : List[List[A]] = xs match {
case Nil => acc
case x :: Nil => List(x) :: acc
case h :: t =>
val (pre,post) = t.span(!splitOn(_))
loop(post, (h :: pre) :: acc)
}
loop(xs, Nil).reverse
}
UPDATE
As requested in comments on the original post, here's a version that enriches list instead of being a standalone method:
implicit class AddMultispanToList[A](val list: List[A]) extends AnyVal {
def multiSpan(splitOn: (A) => Boolean): List[List[A]] = {
#tailrec
def loop(xs: List[A], acc: List[List[A]]) : List[List[A]] = xs match {
case Nil => acc
case x :: Nil => List(x) :: acc
case h :: t =>
val (pre,post) = t.span(!splitOn(_))
loop(post, (h :: pre) :: acc)
}
loop(list, Nil).reverse
}
}
Use as:
myList.multiSpan(_.isInstanceOf[TypeA])
Why couldn't you use partition method from the standard API?
example:
scala> val l = List(3,5,4,6)
l: List[Int] = List(3, 5, 4, 6)
scala>
scala> val (odd,even) = l.partition(_ %2 ==1)
odd: List[Int] = List(3, 5)
even: List[Int] = List(4, 6)
For your example:
scala> val (typeA,typeB) = myList.partition(_.isInstanceOf[TypeA])
typeA: List[Product with Serializable with Item] = List(TypeA(1), TypeA(2), TypeA(3))
typeB: List[Product with Serializable with Item] = List(TypeB(11), TypeB(12), TypeB(21), TypeB(31))
Aren't you looking for filter, which works (almost) without any tweaks for your examples?
$ sbt console
scala> trait Item
scala> case class TypeA(i: Int) extends Item
scala> case class TypeB(i: Int) extends Item
scala> val myList = List(TypeA(1), TypeB(11), TypeB(12),
TypeA(2), TypeB(21),
TypeA(3), TypeB(31))
myList: List[Product with Serializable with Item] = List(TypeA(1), TypeB(11), TypeB(12), TypeA(2), TypeB(21), TypeA(3), TypeB(31))
your first works unaltered:
scala> myList.filter { x => x.isInstanceOf[TypeA] }
res0: List[Product with Serializable with Item] = List(TypeA(1), TypeA(2), TypeA(3))
your second requires a default case:
scala> myList.filter { case TypeA(x) => x < 10; case _ => false }
res2: List[Product with Serializable with Item] = List(TypeA(1(3))
See also collect, which takes a partial function instead of a boolean predicate:
scala> myList.collect { case z # TypeA(x) if x < 10 => z }
res3: List[TypeA] = List(TypeA(1), TypeA(2), TypeA(3))
and can transform as well:
scala> myList.collect { case TypeA(x) if x < 10 => x }
res4: List[Int] = List(1, 2, 3)

Chopping up a list into a list of lists

Suppose I have a list of elements myl and a function f. I would like to chop up myl into a list of lists, where each new "sublist" contains a contiguous stretch of myl on which the value of f is constant.
For example, if myl = List( (1,2), (3,2), (4,1), (6,2) ) and def f(x: (Int, Int)) = x._2. Then the result should be List( List((1,2), (3,2)), List((4, 1)), List((6,2)) ).
Is there an elegant way to write such a function without any vars?
def groupBy[A](as: List[A])(p: (A, A) => Boolean): List[List[A]] =
as.foldRight(List.empty[List[A]]) {
case (x, (ys # y :: _) :: zs) if p(x, y) => (x :: ys) :: zs
case (x, ys) => List(x) :: ys
}
scala> groupBy(myl)(_._2 == _._2)
res0: List[List[(Int, Int)]] = List(List((1,2), (3,2)), List((4,1)), List((6,2)))
Edit: I also wrote this version, using span:
def groupBy[A](as: List[A])(p: (A, A) => Boolean): List[List[A]] =
as match {
case x :: xs =>
val (ys, zs) = xs.span(p(x, _))
(x :: ys) :: groupBy(zs)(p)
case _ => Nil
}
This is essentially similar to ghik's solution, but using pattern matching instead of isEmpty and head.
(An explanation of the name groupBy: there is a function of the same name in the Haskell library, which has this exact same behaviour.)
Little more general solution:
def partitionBy[A](list: List[A])(groupingFunc: A => Any): List[List[A]] =
if (list.nonEmpty) {
val firstGroupingValue = groupingFunc(list.head)
val (group, rest) = list.span(groupingFunc(_) == firstGroupingValue)
group :: partitionBy(rest)(groupingFunc)
} else Nil
Example usage:
scala> partitionBy(List((1,2),(3,2),(5,2),(1,1),(2,1),(3,2),(5,2)))(_._2)
res14: List[List[(Int, Int)]] = List(List((1,2), (3,2), (5,2)), List((1,1), (2,1)), List((3,2), (5,2)))
You could try foldRight
val result2 = l.foldRight(List[List[(Int, Int)]]()) {
(x, acc) =>
if (acc.isEmpty) {
List(x) :: Nil
} else if (acc.head.head._2 == x._2) {
(x :: acc.head) :: acc.tail
} else {
List(x) :: acc
}
}
Your problem is too specific for there to exist a general function solving it, so we'll have to write a function of our own.
The standard strategy to implementing functional algorithms is Divide and conquer, which basically means extracting the smallest part of the problem and then gradually building up the algorithm over it.
Implementation
Okay, the obviously smallest thing we'll need is to test two items for contiguity:
def testContiguity( a : (Int, Int), b : (Int, Int) ) : Boolean
= a._2 == b._2
Then we'll need some function arranging the lists using the two-item comparison function. Would be nice if the standard library had it, but it doesn't, so we define our own:
def arrange
[ A ]
( list : List[ A ] )
( f : (A, A) => Boolean )
: List[ List[ A ] ]
= list match {
case a :: b :: tail =>
if( f(a, b) ) putInFirstGroup( a, arrange( b :: tail )( f ) )
else putInNewGroup( a, arrange( b :: tail )( f ) )
case a :: Nil =>
putInNewGroup( a, Nil )
case Nil =>
Nil
}
Okay, you can see that the above implementation relies on two other functions, let's define them too:
def putInFirstGroup
[ A ]
( item : A, groups : List[ List[ A ] ] )
: List[ List[ A ] ]
= groups match {
case group :: tail =>
(item :: group) :: tail
case Nil =>
(item :: Nil) :: Nil
}
def putInNewGroup
[ A ]
( item : A, groups : List[ List[ A ] ] )
: List[ List[ A ] ]
= (item :: Nil) :: groups
That's it!
Usage
scala> arrange( List( (1,2), (3,2), (4, 1), (6,2) ) )( testContiguity )
res2: List[List[(Int, Int)]] = List(List((1,2), (3,2)), List((4,1)), List((6,2)))
You can now see that we've created a pretty flexible and general solution, working on lists of items of any type and allowing you to use any other testing function to arrange them. Also we've heavily utilized division of a complex algorithm to small easily understandable parts to solve this.