List[List[String]] in Scala - scala

We have a list of strings and i grouping them by below program.
input: val k = List("a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e")
output: *List(List(a, a, a, a), List(b), List(c, c), List(a, a), List(d), List(e, e, e, e))*
Program:
def pack(ls:List[String]):List[List[String]]={
val (a,next) = ls span {_ == ls.head}
if ((next) == Nil) List(a)
else a :: pack(next)
}
However when i do a List cons operators, i get the output as mentioned below.
Input:
val a =List("a", "a", "a", "a")
val b = List ("b")
val c = List ("c", "c" )
val a1 = List("a", "a")
val d = List("d")
val e = List( "e", "e", "e", "e")
*List(a::b::c::a1::d::e)*
output:
*List(List(List(a, a, a, a), List(b), List(c, c), List(a, a), List(d), e, e, e, e))*
Is there any way i can the output as below in a single command in scala?
*List(List(a, a, a, a), List(b), List(c, c), List(a, a), List(d), List(e, e, e, e))*

scala> a::b::c::a1::d::List(e)
res0: List[List[String]] = List(List(a, a, a, a), List(b), List(c, c), List(a, a), List(d), List(e, e, e, e))
The cons operator prepends an item to a list - so construct a List around the last one if you want to then prepend all the other items one by one.
The easiest way to think about this is noticing the types:
To construct a List[List[String]], the cons operator expects to operate on an a List[String] on the left and a List[List[String]] on the right, to produce a new List[List[String]]: on the left should be an item in the resulting list, and on the right - a list with the same type as the expected result
When you write d::e, you're doing List[String] :: List[String], which already means you're not going to produce a List[List[String]] - so the right-hand side must be "wrapped" with a list to get the types right: d::List(e)
Prepending the other items follows the same rule - prepending List[String]s to a List[List[String]]
Once this is done - you get the expected result, without having to wrap the entire result with another list

If you are planning to achieve the end result using ::, adding a Nil at the end to the cons operation could yield the desired result.
a::b::c::a1::d::e::Nil
or you could wrap the last element in a List as #Tzach Zohar has mentioned.
a::b::c::a1::d::List(e)
Otherwise use
List(a,b,c,a1,d,e)

Yes. If you really want to use that syntax:
List(a::b::c::a1::d::e::Nil: _*)
You need the : _* at the end because otherwise you are passing a single element (of type List) to List.apply() and it is not interpreting it as a sequence, which is why you get List[List[List]] instead of the desired List[List].

Related

Scala - Dequeue doesn't return correct result

I have a queue of List[Any], but somehow dequeue doesn't return correct result and it doesn't remove the item from the queue either. Any idea why this happened?
Here is an example:
scala> val a = scala.collection.immutable.Queue(List(1, "A", "B", 987), List(2, "C", "D", 456), List(3, "E", "F", 123))
a: scala.collection.immutable.Queue[List[Any]] = Queue(List(1, A, B, 987), List(2, C, D, 456), List(3, E, F, 123))
scala> a.dequeue
res5: (List[Any], scala.collection.immutable.Queue[List[Any]]) = (List(1, A, B, 987),Queue(List(2, C, D, 456), List(3, E, F, 123)))
scala> a
res6: scala.collection.immutable.Queue[List[Any]] = Queue(List(1, A, B, 987), List(2, C, D, 456), List(3, E, F, 123))
You used an immutable queue, so dequeue does not modify the original queue but rather returns a modified one together with the head element as tuple:
val (elem, newQ) = oldQ.dequeue
For example, you can feed the tail queue into a recursive call for processing. Something like this:
def pq(q: Queue[List[Any]]): Unit = {
q.dequeue match {
case (head, tail) =>
println(head + "..."); // ... process head element ...
if (tail.nonEmpty) pq(tail)
}
}

How to write an expression which generates all possible pairs regardless of order?

I want to make an interface for entering something akin to a covariance matrix. For this, I need to create all empty "cells" in which the data will be entered. But of course, I don't want the user to enter the covariance of A and B when he has already entered the covariance of B and A.
Let's assume that I have the data points A through D as a List("A", "B", "C", "D"). I can then write the expression
val dataPoints = List("A", "B", "C", "D")
for(firstDataPoint <- dataPoints; secondDataPoint <- dataPoints)
yield (firstDataPoint, secondDataPoint)
This gives me all possible combinations, and I can create one "cell" per combination, but the trouble is that both ("A", "B") and ("B", "A") are present.
The only idea I can come up with is to create an empty mutable collection, loop over the result of the above code, check if the opposite pair is already in the mutable collection, and if not, write it into the mutable collection. But this solution seems like bad Scala style to me, and also inefficient (why create all values and immediately discard almost half?) I also want to learn to be better in functional programming, and while Scala has the tools for me to do that, it wouldn't have worked in a purely functional language.
Note that my actual data points don't have an inherent ordering, so I can't say that I throw out all combinations where secondDataPoint<firstDataPoint.
Is there a smarter way to do that?
Since your elements are not ordered, you can do that by checking order of your elements in a list (since a list is ordered by index of an element). So, just check if the indexes are different:
val dataPoints = List("A", "B", "C", "D")
for(firstDataPoint <- dataPoints; secondDataPoint <- dataPoints)
if(dataPoints.indexOf(firstDataPoint) >= dataPoints.indexOf(secondDataPoint)){
yield (firstDataPoint, secondDataPoint)
}
}
Variant of #user987339's answer that removes the O(N) indexOf. #user987339, feel free to include this in your answer and I'll delete this one, it's only a minor tweak to yours.
val dataPoints = List("A", "B", "C", "D")
val indexedDataPoints = dataPoints zipWithIndex
for(firstDataPoint <- indexedDataPoints; secondDataPoint <- indexedDataPoints)
if(firstDataPoint._2) >= secondDataPoint._2)){
yield (firstDataPoint._1, secondDataPoint._1)
}
}
Just use the built-in combinations method:
List("A", "B", "C", "D").combinations(2)
This returns an Iterator. It should be enough for most purposes, but you can of course convert it to List to look at the results:
scala> List("A", "B", "C", "D").combinations(2).toList
res1: List[List[String]] = List(List(A, B), List(A, C), List(A, D), List(B, C), List(B, D), List(C, D))
As you see it also doesn't include pairs of the same element (e.g., List("A", "A")). It might be OK for your purposes (as in a correlation matrix all elements on the principal diagonal are trivially equal to 1). But you can add them if you want:
scala> val dataPoints = List("A", "B", "C", "D")
scala> (dataPoints.combinations(2) ++
(dataPoints map (el => List(el, el)))).toList
res2: List[List[String]] = List(List(A, B), List(A, C), List(A, D), List(B, C), List(B, D), List(C, D), List(A, A), List(B, B), List(C, C), List(D, D))

scala partial string match

I have a question about List of Strings partial Matching to a List of Strings (intersect I guess).
List1:List = [a,b,c,d,e,f]
List2:Iterable[String] = [a b,e f,g h,x y]
I want to take any element or combination of elements in List1 that also happens to be in List2, and replace it with the element in List2, for example, [a,b] are in List1, List 2 contains element [a b], in this case, [a,b] in List1 will be replaced with [a b]. The result for List 1 should be:
List1result = [a b,c,d,e f]
I've tried intersect, which would return [a b, e f]
Ok, I edited my answer after the comment bellow, I think I understood the question now.
take each element of the second list, convert it into a list of elements and use containsSlice to filter out the value.
containsSlice will return true if all the elements in the slice are present in the first list.
val lst1 = List("a","b","c","d","e","f")
val lst2 = List("a b","e f","g h","x y")
lst2.filter{ pair =>
val xss = pair.split(" ")
lst1.containsSlice(xss)
}
You can try something like this :
val l1 = List("a", "b", "c", "d", "e", "f")
val l2 = List("a b", "e f", "g h", "x y")
l1.filterNot(x=>l2.flatten.filter(_ != ' ').contains(x.toCharArray.head))
l2.foldLeft(List[String]()) { case (x, y) => if (l1.containsSlice(y.split(" "))) x :+ y else x} ++
l1.filterNot(x=>l2.flatten.filter(_ != ' ').contains(x.toCharArray.head))
l1: List[String] = List(a, b, c, d, e, f)
l2: List[String] = List(a b, e f, g h, x y)
res0: List[String] = List(a b, e f, c, d)

In Scala, how do you combine the sequence of elements of the same List?

How do I transform this list:
List("a", "b", "c", "d")
into a list with the following elements
List(List("a"), List("a", "b"), List("a", "b", "c"), List("a", "b", "c", "d"))
My requirement is to build a list of relative directory paths from a list containing directory names, where a is the root directory and b is a leaf of a i.e. a/b
Example:
"fruit", "tropical", "mango"
transforms to:
"fruit", "fruit/tropical", "fruit/tropical/mango"
Edit: I can do this iteratively, but I'm looking for a functional solution.
You can use inits to achieve similar thing you are looking for:
val xs = List("a", "b", "c", "d")
val ys = xs.inits.toList.reverse.drop(1)
Explanation:
xs.inits.toList will give you this result:
List(List(a, b, c, d), List(a, b, c), List(a, b), List(a), List())
Now you can reverse it and drop the first element and get this:
List(List(a), List(a, b), List(a, b, c), List(a, b, c, d))
Then, just make a String of results you got:
ys.map(_.mkString("/")) // results in List(a, a/b, a/b/c, a/b/c/d)
I think you should probably use inits (I would avoid relying on the order of the returned elements, although it is documented that the last element is the empty one):
val basket = List("fruit", "tropical", "mango")
basket.inits.toList filterNot (_.isEmpty) sortBy (_.length) map (_ mkString "/")
However, if you want an approach that doesn't use that library function, you could roll your own recursive function:
def paths(elems: List[String]): List[List[String]] = {
elems match {
case Nil => Nil
case e :: es => List(e) :: (paths(es) map (e :: _))
}
}
paths(basket) map (_ mkString "/")
This isn't tail-recursive, so it will blow the stack if your path is many elements deep. You could make it tail-recursive using an accumulating parameter (actually, two accumulating parameters is the best I can do):
#annotation.tailrec
final def paths(elems: List[String], path: List[String], acc: List[List[String]]): List[List[String]] = {
elems match {
case Nil => acc
case e :: es => paths(es, path :+ e, acc :+ (path :+ e))
}
}
paths(basket, Nil, Nil) map (_ mkString "/")
This solution uses the :+ operator (append element) on List a lot though, so it's not optimal with respect to time complexity. I'll leave fixing that as an exercise for the reader (hint: you would probably want to store the accumulating parameters in reverse order).

Cartesian product of two lists

Given a map where a digit is associated to several characters
scala> val conversion = Map("0" -> List("A", "B"), "1" -> List("C", "D"))
conversion: scala.collection.immutable.Map[java.lang.String,List[java.lang.String]] =
Map(0 -> List(A, B), 1 -> List(C, D))
I want to generate all possible character sequences based on a sequence of digits. Examples:
"00" -> List("AA", "AB", "BA", "BB")
"01" -> List("AC", "AD", "BC", "BD")
I can do this with for comprehensions
scala> val number = "011"
number: java.lang.String = 011
Create a sequence of possible characters per index
scala> val values = number map { case c => conversion(c.toString) }
values: scala.collection.immutable.IndexedSeq[List[java.lang.String]] =
Vector(List(A, B), List(C, D), List(C, D))
Generate all the possible character sequences
scala> for {
| a <- values(0)
| b <- values(1)
| c <- values(2)
| } yield a+b+c
res13: List[java.lang.String] = List(ACC, ACD, ADC, ADD, BCC, BCD, BDC, BDD)
Here things get ugly and it will only work for sequences of three digits. Is there any way to achieve the same result for any sequence length?
The following suggestion is not using a for-comprehension. But I don't think it's a good idea after all, because as you noticed you'd be tied to a certain length of your cartesian product.
scala> def cartesianProduct[T](xss: List[List[T]]): List[List[T]] = xss match {
| case Nil => List(Nil)
| case h :: t => for(xh <- h; xt <- cartesianProduct(t)) yield xh :: xt
| }
cartesianProduct: [T](xss: List[List[T]])List[List[T]]
scala> val conversion = Map('0' -> List("A", "B"), '1' -> List("C", "D"))
conversion: scala.collection.immutable.Map[Char,List[java.lang.String]] = Map(0 -> List(A, B), 1 -> List(C, D))
scala> cartesianProduct("01".map(conversion).toList)
res9: List[List[java.lang.String]] = List(List(A, C), List(A, D), List(B, C), List(B, D))
Why not tail-recursive?
Note that above recursive function is not tail-recursive. This isn't a problem, as xss will be short unless you have a lot of singleton lists in xss. This is the case, because the size of the result grows exponentially with the number of non-singleton elements of xss.
I could come up with this:
val conversion = Map('0' -> Seq("A", "B"), '1' -> Seq("C", "D"))
def permut(str: Seq[Char]): Seq[String] = str match {
case Seq() => Seq.empty
case Seq(c) => conversion(c)
case Seq(head, tail # _*) =>
val t = permut(tail)
conversion(head).flatMap(pre => t.map(pre + _))
}
permut("011")
I just did that as follows and it works
def cross(a:IndexedSeq[Tree], b:IndexedSeq[Tree]) = {
a.map (p => b.map( o => (p,o))).flatten
}
Don't see the $Tree type that am dealing it works for arbitrary collections too..