How does containTheSameElementsAs work in specs2 - scala

This code does not match. Is this correct?
List(1, List(2, 3, List(4)), 5) must containTheSameElementsAs(List(5, List(List(4), 2, 3), 1))
Error message is following:
[error] x be available for elements in a sequence
[error] List(1, List(2, 3, List(4)), 5)
[error] is missing: List(List(4), 2, 3)
[error] must not contain: List(2, 3, List(4)) (specs2test.scala:98)

The containsTheSameElementsAs matcher only goes one level deep, so the match fails on your nested list as List(2, 3, List(4)) != List(List(4), 2, 3). It might be better to simply flatten your nested object before using this matcher.

Related

Scala Match Error Case Prevention

I have this function that basically combines Lists of Lists, but you can ignore that, for that is not the issue:
def combinationList[T](ls:List[List[List[T]]]) : List[List[List[T]]] = ls match {
case head :: Nil => for(x <- head) yield List(x)
case head :: tail :: Nil =>
for {
hl <- head
tl <- tail
if tl.forall(te => !hl.contains(te))
} yield List(hl, tl)
}
This works when I have a List with two sub-lists but it fails to match when I have more than two. I obviously need to use this function recursively to make a more general case, and I've tried to add the following case at the end of the function:
case _ => combinationList(combinationList(ls.tail):::List(ls.head))
The logic here is that, imagine we have a List with 3 sub lists, like so:
List ( List(1), List(2), List(3) )
When I first call the fucntion, it will only match in the last case I mentioned, so, I will call the function with the list's tail (List(2), List(3)), and, in that call, it will match for the second case (head::tail::Nil), then, when it returns, it should be a single List and when added to the list's original head (List(1)::List(2+3)) it should match on the second condition. The issue here is that the return is not a single list (List(2+3)) but rather yet another combination of lists (List(2), List(3)) so it will obviously recursive forever. I've tried to modify the case like this:
combinationList(List(combinationList(ls.tail)):::List(ls.head))
But it gives me an error ("The expression of type List[List[List[Any]]] doesn't conform to type List[List[List[T]]]"
Any ideas? Thanks.
[EDIT:] This function's purpose is to combine lists in such manner:
simplified input: List( List(1,2), List(3), List(4))
simplified output: List( List(1,3,4), List(2,3,4))
real input: List(
List(List(1), List(3), List(4)),
List(List(2), List(3), List(4))
)
real expected output: List(
List(List(1), List(2)),
List(List(1), List(3)),
List(List(1), List(4)),
List(List(3), List(2)),
List(List(3), List(4)),
List(List(4), List(2)),
List(List(4), List(3))
)
With the real input, the function is able to return the expected output, it only fails when another sub list is added, like so:
input: List(
List(List(1), List(2)),
List(List(3), List(4)),
List(List(5))
)
The expected output here, would be:
expected output: List(
List(List(1), List(3), List(5)),
List(List(1), List(4), List(5)),
List(List(2), List(3), List(5)),
List(List(2), List(4), List(5))
)
So, the order of the combinations don't really matter much, I can head:::tail or tail:::head, it's the same thing.
I still don't know why you want three levels of nesting. However, the following generic method works with all your examples, both with integers and with lists:
def combinationList[T](ls: List[List[T]]): List[List[T]] = {
def recHelper(remainingLs: List[List[T]], blacklist: Set[T]): List[List[T]] = {
remainingLs match {
case Nil => List(Nil)
case h :: t => for {
x <- h.filterNot(blacklist.contains)
xs <- recHelper(t, blacklist + x)
} yield x :: xs
}
}
recHelper(ls, Set.empty)
}
This implementation doesn't filter out any combinations with ! .contains, instead it maintains a set of blacklisted elements, and doesn't generate the invalid combinations in the first place.
Some examples:
def showExample[T](input: List[List[T]]): Unit = {
println("=" * 60)
println(input)
println("-" * 60)
for (c <- combinationList(input)) {
println(" " + c)
}
}
showExample(List(List(1, 2), List(3), List(4)))
showExample(List(List(1, 2, 3), List(2, 3, 4), List(2, 3, 5)))
showExample(List(
List(List(1), List(3), List(4)),
List(List(2), List(3), List(4))
))
showExample(List(
List(List(1), List(2)),
List(List(3), List(4)),
List(List(5))
))
Output:
============================================================
List(List(1, 2), List(3), List(4))
------------------------------------------------------------
List(1, 3, 4)
List(2, 3, 4)
============================================================
List(List(1, 2, 3), List(2, 3, 4), List(2, 3, 5))
------------------------------------------------------------
List(1, 2, 3)
List(1, 2, 5)
List(1, 3, 2)
List(1, 3, 5)
List(1, 4, 2)
List(1, 4, 3)
List(1, 4, 5)
List(2, 3, 5)
List(2, 4, 3)
List(2, 4, 5)
List(3, 2, 5)
List(3, 4, 2)
List(3, 4, 5)
============================================================
List(List(List(1), List(3), List(4)), List(List(2), List(3), List(4)))
------------------------------------------------------------
List(List(1), List(2))
List(List(1), List(3))
List(List(1), List(4))
List(List(3), List(2))
List(List(3), List(4))
List(List(4), List(2))
List(List(4), List(3))
============================================================
List(List(List(1), List(2)), List(List(3), List(4)), List(List(5)))
------------------------------------------------------------
List(List(1), List(3), List(5))
List(List(1), List(4), List(5))
List(List(2), List(3), List(5))
List(List(2), List(4), List(5))
Some hints:
The more generic versions of the code are often easier to write, because if there are more constraints, there are fewer possibilities to do something wrong. In this case, the triple nesting seems unnecessary.
The base case is the empty list, not the list with one element
The recursion must work with lists of arbitrary length, but x :: y :: Nil matches only lists of length two.

Difference between flatMap and flatten in Scala [duplicate]

scala> List(List(1), List(2), List(3), List(4))
res18: List[List[Int]] = List(List(1), List(2), List(3), List(4))
scala> res18.flatten
res19: List[Int] = List(1, 2, 3, 4)
scala> res18.flatMap(identity)
res20: List[Int] = List(1, 2, 3, 4)
Is there any difference between these two functions? When is it appropriate to use one over the other? Are there any tradeoffs?
You can view flatMap(identity) as map(identity).flatten. (Of course it is not implemented that way, since it would take two iterations).
map(identity) gives you the same collection, so in the end it is the same as only flatten.
I would personally stick to flatten, since it is shorter/easier to understand and designed to exactly do this.
Conceptually there is no difference in the result... flatMap is taking
bit more time to produce same result...
I will show it more practically with an example of flatMap, map & then flatten and flatten
object Test extends App {
// flatmap
println(timeElapsed(List(List(1, 2, 3, 4), List(5, 6, 7, 8)).flatMap(identity)))
// map and then flatten
println(timeElapsed(List(List(1, 2, 3, 4), List(5, 6, 7, 8)).map(identity).flatten))
// flatten
println(timeElapsed(List(List(1, 2, 3, 4), List(5, 6, 7, 8)).flatten))
/**
* timeElapsed
*/
def timeElapsed[T](block: => T): T = {
val start = System.nanoTime()
val res = block
val totalTime = System.nanoTime - start
println("Elapsed time: %1d nano seconds".format(totalTime))
res
}
}
Both flatMap and flatten executed with same result after repeating several times
Conclusion : flatten is efficient
Elapsed time: 2915949 nano seconds
List(1, 2, 3, 4, 5, 6, 7, 8)
Elapsed time: 1060826 nano seconds
List(1, 2, 3, 4, 5, 6, 7, 8)
Elapsed time: 81172 nano seconds
List(1, 2, 3, 4, 5, 6, 7, 8)
Conceptually, there is no difference. Practically, flatten is more efficient, and conveys a clearer intent.
Generally, you don't use identity directly. It's more there for situations like it getting passed in as a parameter, or being set as a default. It's possible for the compiler to optimize it out, but you're risking a superfluous function call for every element.
You would use flatMap when you need to do a map (with a function other than identity) immediately followed by a flatten.

Scala: List of vectors to Unique List of items in immutable way

I am receiving list of vectors from some function like
(List(Vector(1), Vector(1, 2), Vector(1, 3), Vector(1, 2, 4), Vector(1, 5)))
I want to convert it into distinct values of integers like
List(1,2,3,4,5)
in Scala using complete immutability.
Please suggest what are the efficient ways to achieve it.
You can use the flatten and distinct methods on List.
val list = List(Vector(1),
Vector(1, 2),
Vector(1, 3),
Vector(1, 2, 4),
Vector(1, 5))
val flattened = list.flatten // Gives List(1, 1, 2, 1, 3, 1, 2, 4, 1, 5)
val distinct = flattened.distinct // Gives List(1, 2, 3, 4, 5)
Here is alternate solution.
val lst = (List(Vector(1), Vector(1, 2), Vector(1, 3), Vector(1, 2, 4), Vector(1, 5)))
lst.flatten.toSet.toList
List[Int] = List(5, 1, 2, 3, 4)

Are combinations and permutations stable in Scala collections?

Should I rely on the order of combinations and permutations generated by corresponding methods of Scala's collections? For example:
scala> Seq(1, 2, 3).combinations(2).foreach(println)
List(1, 2)
List(1, 3)
List(2, 3)
Can I be sure that I will get my results always in the same precise order?
Well the documentation does not says anything on the order. It just says:
An Iterator which traverses the possible n-element combinations of
this sequence.
So it doesn't guarantee.
Ideally you should always get the order as you printed but it is not guaranteed by the library. So its (pessimistic) safe not to trust it and rather do sort it so that you get the same series always:
scala> import scala.math.Ordering.Implicits._
import scala.math.Ordering.Implicits._
scala> Seq(1,2,3).combinations(2).toList.sorted.foreach(println)
List(1, 2)
List(1, 3)
List(2, 3)
The combinations implementation maintains the order of the elements in the given sequence.
Except that input is processed to group repeated elements together.
The output is not sorted.
scala> Seq(3,2,1).combinations(2).toList
res1: List[Seq[Int]] = List(List(3, 2), List(3, 1), List(2, 1))
The sequence is updated to keep repeated elements together. For instance:
scala> Seq(2,1,3,1,2).combinations(2).toList
res2: List[Seq[Int]] = List(List(2, 2), List(2, 1), List(2, 3), List(1, 1), List(1, 3))
in this case seq is first converted to Seq(2,2,1,1,3):
scala> Seq(2,2,1,1,3).combinations(2).toList
res3: List[Seq[Int]] = List(List(2, 2), List(2, 1), List(2, 3), List(1, 1), List(1, 3))
scala> res2 == res3
res4: Boolean = true

Selecting the Minumum Sized List in a List of List

I have list of list of integers.
List(List(1, 1, 1, 1), List(2, 1, 1), List(2, 2))
I want to get the minimum sized list from that list which is List(2,2).
What is the recommended way of doing this in Scala ?
Almost duplicate of another question that was asked today:
val xs = List(List(1, 1, 1, 1), List(2, 1, 1), List(2, 2))
xs.minBy(list => list.length)
// res0: List[Int] = List(2, 2)