Get subsets of a range of sizes in Scala? - scala

I can get subsets of a specific size or all of them.
scala> println((1 to 25).toSet.subsets.size)
33554432
scala> println((1 to 25).toSet.subsets(1).size)
25
scala> println((1 to 25).toSet.subsets(10).size)
1
To get just the subsets of size, say 10 or less, I could fall back to a loop and take the union. What would be a functional programming way of doing this?

You can use flatMap as follows:
(1 to 10).flatMap((1 to 25).toSet.subsets(_))
For example, below is a list of all subsets of size up to 3 in a Set of 6 elements:
(1 to 3).flatMap((1 to 6).toSet.subsets(_))
// res1: scala.collection.immutable.IndexedSeq[scala.collection.immutable.Set[Int]] = Vector(
// Set(5), Set(1), Set(6), Set(2), Set(3), Set(4),
// Set(5, 1), Set(5, 6), Set(5, 2), Set(5, 3), Set(5, 4), Set(1, 6),
// Set(1, 2), Set(1, 3), Set(1, 4), Set(6, 2), Set(6, 3), Set(6, 4),
// Set(2, 3), Set(2, 4), Set(3, 4),
// Set(5, 1, 6), Set(5, 1, 2), Set(5, 1, 3), Set(5, 1, 4), Set(5, 6, 2),
// Set(5, 6, 3), Set(5, 6, 4), Set(5, 2, 3), Set(5, 2, 4), Set(5, 3, 4),
// Set(1, 6, 2), Set(1, 6, 3), Set(1, 6, 4), Set(1, 2, 3), Set(1, 2, 4),
// Set(1, 3, 4), Set(6, 2, 3), Set(6, 2, 4), Set(6, 3, 4), Set(2, 3, 4)
// )

I think this is what you're after. (Using smaller numbers for visual verification.)
(2 to 4).flatMap(Set(1 to 5:_*).subsets)
//res0 = Vector(Set(5, 1), Set(5, 2), Set(5, 3), Set(5, 4), Set(1, 2), Set(1, 3), Set(1, 4), Set(2, 3), Set(2, 4), Set(3, 4), Set(5, 1, 2), Set(5, 1, 3), Set(5, 1, 4), Set(5, 2, 3), Set(5, 2, 4), Set(5, 3, 4), Set(1, 2, 3), Set(1, 2, 4), Set(1, 3, 4), Set(2, 3, 4), Set(5, 1, 2, 3), Set(5, 1, 2, 4), Set(5, 1, 3, 4), Set(5, 2, 3, 4), Set(1, 2, 3, 4))

Related

All combinations of arbitrary number of sets using for comprehension

Let's look at following source of code:
def foo(s1: Set[Int], s2: Set[Int], s3: Set[Int]): Set[Set[Int]] = {
for {
ss1 <- s1
ss2 <- s2
ss3 <- s3
} yield Set(ss1, ss2, ss3)
}
How to define analogous function for def foo(ss: Set[Int]*) ?
It's almost the same as the usual cartesian product, except that you have to cram all the results into sets instead of collecting them in ordered tuples:
/** Forms cartesian product of sets,
* then collapses each resulting tuple into a set.
*/
def collapsedCartesian[A](sets: Set[A]*): Set[Set[A]] = sets match
case Seq() => Set(Set.empty)
case Seq(h, t # _*) => for a <- h; b <- collapsedCartesian(t: _*) yield (b + a)
Note that here, the + adds an element to a set: set + elem, which is an oddly asymmetric operation to be denoted by such a symmetric symbol.
The outcome seems reasonably irregular:
collapsedCartesian(Set(1, 2), Set(3, 4)).foreach(println)
println("---")
collapsedCartesian(Set(1, 2), Set(1, 2)).foreach(println)
println("---")
collapsedCartesian(Set(1, 2, 3), Set(4, 5), Set(6, 7)).foreach(println)
println("---")
collapsedCartesian(Set(1, 2, 3), Set(2, 3, 4), Set(4, 5)).foreach(println)
gives:
Set(3, 1)
Set(4, 1)
Set(3, 2)
Set(4, 2)
---
Set(1)
Set(2, 1)
Set(2)
---
Set(7, 5, 1)
Set(6, 4, 2)
Set(6, 4, 1)
Set(7, 4, 1)
Set(6, 5, 1)
Set(7, 5, 3)
Set(7, 4, 2)
Set(6, 5, 2)
Set(6, 4, 3)
Set(7, 5, 2)
Set(7, 4, 3)
Set(6, 5, 3)
---
Set(5, 3, 1)
Set(5, 4, 2)
Set(5, 4, 1)
Set(4, 2)
Set(4, 1)
Set(5, 3)
Set(5, 3, 2)
Set(5, 4, 3)
Set(4, 2, 1)
Set(5, 2, 1)
Set(4, 3, 1)
Set(4, 3, 2)
Set(5, 2)
Set(4, 3)
Please don't ask how to do it in Spark, this exponentially exploding stuff is obviously useless for any dataset with more than just a couple of entries.

Scala's List unpacking

So my problem is simple. I have come across this many times, and my brain is unable to find a solution.
How can I unpack a list into another list, for an indefinite amount of variables?
Here is what I mean.
val list1 = List(List(7, 4), List(7, 6))
val list2 = List(List(1), List(5), List(8))
val desired_list1 = List(List(1, 7, 4), List(5, 7, 4), List(8, 7, 4))
val desired_list2 = List(List(1, 7, 6), List(5, 7, 6), List(8, 7, 6))
//** The desired_list1 and 2 must be a List[List[Int]] it cannot be List[List[Any]]
//Here's my attempt, which oddly enough completely ignores all elements of list1(0) which are not the first(7).
val attempt = list2.map(i => i +: list1(0)).map(j => j.collect{ case k:Int => k; case l # a :: b => a}).map(m => m.map{ case i:Any => i.toString.toInt})
//The result is
attempt: List[List[Int]] = List(List(1, 7), List(5, 7), List(8, 7))
//while it should be:
val desired_list1 = List(List(1, 7, 4), List(5, 7, 4), List(8, 7, 4))
I need a way to unpack that is not manual, please do not tell me to do this:
val attempt = list2.map(k => k +: list1(0)).map{ case (k, List(x, y)) => (k, x, y)}
Basically, list1 could have any number of elements. e.g
val list1 = List(List(99, 83, 2, 3, 4), List(99, 83, 2, 5 7))
However, these numbers are never repeated, so I guess it could be a set as well. But I don't know much about sets or if it'd help in any way.
This seems to be what you want:
val lists: List[List[Int]] = List(List(7, 4), List(7, 6))
val prefixes: List[List[Int]] = List(List(1), List(5), List(8))
val res: List[List[Int]] = for{
prefix <- prefixes.flatten
rest <- lists
} yield prefix :: res
// res: List[List[Int]] = List(List(1, 7, 4), List(1, 7, 6), List(5, 7, 4), List(5, 7, 6), List(8, 7, 4), List(8, 7, 6))
Unless, you actually want a list that contains your desired_list1 and desired_list2 together, in which case you need:
val res3 = lists.map{ rest =>
prefixes.flatten.map{prefix =>
prefix :: rest
}
}
/// res3: List[List[List[Int]]] =
// List(
// List(
// List(1, 7, 4), List(5, 7, 4), List(8, 7, 4)
// ),
// List(
// List(1, 7, 6), List(5, 7, 6), List(8, 7, 6)
// )
// )
I am not sure exactly why you would want that but try this out:
val list1 = List(List(7, 4), List(7, 6))
val list2 = List(1, 5, 8)
list2.flatMap(element=> list1.map(innerList=> element:: innerList))
output: List[List[Int]] = List(List(1, 7, 4), List(1, 7, 6), List(5, 7, 4), List(5, 7, 6), List(8, 7, 4), List(8, 7, 6))

How to summarize lists in Scala?

to All!
i have this data structure:
List[List[String]]
all List[String] are the same size, it looks like:
List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
i need to summarize columns in this lists like this:
val result = List(1 + 4 + 7, 2 + 5 + 8, 3 + 6 + 9)
with such algorithm
res[0] = list1[0] + list2[0] + list3[0]
res[1] = list1[1] + list2[2] + list3[3]
...
help, please!
You're looking for the transpose method:
scala> val in = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
in: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
scala> in.transpose
res0: List[List[Int]] = List(List(1, 4, 7), List(2, 5, 8), List(3, 6, 9))
scala> in.transpose.map(_.sum)
res1: List[Int] = List(12, 15, 18)

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)

Idiomatic scala solution to combining sequences

Imagine a function combineSequences: (seqs: Set[Seq[Int]])Set[Seq[Int]] that combines sequences when the last item of first sequence matches the first item of the second sequence. For example, if you have the following sequences:
(1, 2)
(2, 3)
(5, 6, 7, 8)
(8, 9, 10)
(3, 4, 10)
The result of combineSequences would be:
(5, 6, 7, 8, 8, 9, 10)
(1, 2, 2, 3, 3, 4, 10)
Because sequences 1, 2, and 5 combine together. If multiple sequences could combine to create a different result, the decisions is arbitrary. For example, if we have the sequences:
(1, 2)
(2, 3)
(2, 4)
There are two correct answers. Either:
(1, 2, 2, 3)
(2, 4)
Or:
(1, 2, 2, 4)
(2, 3)
I can only think of a very imperative and fairly opaque implementation. I'm wondering if anyone has a solution that would be more idiomatic scala. I've run into related problems a few times now.
Certainly not the most optimized solution but I've gone for readability.
def combineSequences[T]( seqs: Set[Seq[T]] ): Set[Seq[T]] = {
if ( seqs.isEmpty ) seqs
else {
val (seq1, otherSeqs) = (seqs.head, seqs.tail)
otherSeqs.find(_.headOption == seq1.lastOption) match {
case Some( seq2 ) => combineSequences( otherSeqs - seq2 + (seq1 ++ seq2) )
case None =>
otherSeqs.find(_.lastOption == seq1.headOption) match {
case Some( seq2 ) => combineSequences( otherSeqs - seq2 + (seq2 ++ seq1) )
case None => combineSequences( otherSeqs ) + seq1
}
}
}
}
REPL test:
scala> val seqs = Set(Seq(1, 2), Seq(2, 3), Seq(5, 6, 7, 8), Seq(8, 9, 10), Seq(3, 4, 10))
seqs: scala.collection.immutable.Set[Seq[Int]] = Set(List(1, 2), List(2, 3), List(8, 9, 10), List(5, 6, 7, 8), List(3, 4, 10))
scala> combineSequences( seqs )
res10: Set[Seq[Int]] = Set(List(1, 2, 2, 3, 3, 4, 10), List(5, 6, 7, 8, 8, 9, 10))
scala> val seqs = Set(Seq(1, 2), Seq(2, 3, 100), Seq(5, 6, 7, 8), Seq(8, 9, 10), Seq(100, 4, 10))
seqs: scala.collection.immutable.Set[Seq[Int]] = Set(List(100, 4, 10), List(1, 2), List(8, 9, 10), List(2, 3, 100), List(5, 6, 7, 8))
scala> combineSequences( seqs )
res11: Set[Seq[Int]] = Set(List(5, 6, 7, 8, 8, 9, 10), List(1, 2, 2, 3, 100, 100, 4, 10))