How to create LazyList Scala using LazyList.iterate? - scala

My task:
Implement a function to calculate the Look-and-say sequence.
This is done and the tests pass successfully:
import scala.collection.immutable.LazyList
import scala.language.implicitConversions
import scala.collection.mutable.ListBuffer
object CountAndSay extends App {
def nextLine(currentLine: List[BigInt]): List[BigInt] = {
...
println(nextLine(List(1, 2, 1, 1)) == List(1, 1, 1, 2, 2, 1))
println(nextLine(List(1, 1, 1, 2, 2, 1)) == List(3, 1, 2, 2, 1, 1))
println(nextLine(List(3, 1, 2, 2, 1, 1)) == List(1, 3, 1, 1, 2, 2, 2, 1))
}
Implement a lazy list that generates the given sequence.
val funSeq: LazyList[List[Int]] = ...
println(funSeq(5) === List(3, 1, 2, 2, 1, 1))
To create a LazyList with nested lists, I want to use LazyList.iterate.
LazyList.iterate description
But I get a Cannot resolve overloaded method 'iterate' error:
val funSeq: LazyList[List[BigInt]] = LazyList.iterate(List(1), nextLine(List(1)))
I would appreciate any help.

It looks like you do not use LazyList syntax correctly. You need to use it as follow:
LazyList.iterate(List(BigInt(1)))(nextLine).take(4).force
First parameter of iterate is start element that will passed in the function - second parameter of iterate. The take need to do several iterations and force need to evaluate result.

Related

Printing specific output in Scala

I have the following array of arrays that represents a cycle in a graph that I want to print in the below format.
scala> result.collect
Array[Array[Long]] = Array(Array(0, 1, 4, 0), Array(1, 5, 2, 1), Array(1, 4, 0, 1), Array(2, 3, 5, 2), Array(2, 1, 5, 2), Array(3, 5, 2, 3), Array(4, 0, 1, 4), Array(5, 2, 3, 5), Array(5, 2, 1, 5))
0:0->1->4;
1:1->5->2;1->4->0;
2:2->3->5;2->1->5;
3:3->5->2;
4:4->0->1;
5:5->2->3;5->2->1;
How can I do this? I have tried to do a for loop with if statements like other coding languages but scala's ifs in for loops are for filtering and cannot make use if/else to account for two different criteria.
example python code
for (array,i) in enumerate(range(0,result.length)):
if array[i] == array[i+1]:
//print thing needed
else:
// print other thing
I also tried to do result.groupBy to make it easier to print but doing that ruins the arrays.
Array[(Long, Iterable[Array[Long]])] = Array((4,CompactBuffer([J#3677a08a)), (0,CompactBuffer([J#695fd7e)), (1,CompactBuffer([J#50b0f441, [J#142efc4d)), (3,CompactBuffer([J#1fd66db2)), (5,CompactBuffer([J#36811d3b, [J#61c4f556)), (2,CompactBuffer([J#2eba1b7, [J#2efcf7a5)))
Is there a way to nicely print the output needed in Scala?
This should do it:
result
.groupBy(_.head)
.toArray
.sortBy(_._1)
.map {
case (node, cycles) =>
val paths = cycles.map { cycle =>
cycle
.init // drop last node
.mkString("->")
}
s"$node:${paths.mkString(";")}"
}
.mkString(";\n")
This is the output for the sample input you provided:
0:0->1->4;
1:1->5->2;1->4->0;
2:2->3->5;2->1->5;
3:3->5->2;
4:4->0->1;
5:5->2->3;5->2->1

Scala collection select elements until first one meet a requirement

For example I have following Scala list, I want get a sublist until there is a requirement can be met.
val list = Seq(1,2,3,4,5,5,4,1,2,5)
The requirement is the number is 5, so I want the result as:
Seq(1,2,3,4)
Currently I use Scala collection's indexWhere and splitAt to return:
list.splitAt(list.indexWhere(x => x == 5))
(Seq(1,2,3,4), Seq(5,5,4,1,2,5))
I am not sure there are more better ways to achieve the same with better Scala collection's method I didn't realise?
You can use takeWhile:
scala> val list = Seq(1,2,3,4,5,5,4,1,2,5)
list: Seq[Int] = List(1, 2, 3, 4, 5, 5, 4, 1, 2, 5)
scala> list.takeWhile(_ != 5)
res30: Seq[Int] = List(1, 2, 3, 4)
Use span like this,
val (l,r) = list.span(_ != 5)
which delivers
l: List(1, 2, 3, 4)
r: List(5, 5, 4, 1, 2, 5)
Alternatively, you can write
val l = list.span(_ != 5)._1
to access only the first element of the resulting tuple.
This bisects the list at the first element that does not hold the condition.

Flattening a list of lists to a set with exceptions in scala

This feels like a peculiar problem and I am very new to Scala, so I don't know how to ask the right questions in order to get progress on this problem.
As a demonstration, say I have a list of lists like this:
val data = List(List(1, 2, 3, 4), List(1, 2, 2, 3, 4), List(1, 2, 3, 3, 3, 4), List(1, 2, 3, 4), List(2, 3, 4))
and I want to be able to reduce it down to a List of integers that looks mostly like a distinct set of the multiple lists, with one exception: where each list has more than one of each integer, I want to represent that in the final list. So as a general rule, the list with the most representations of that integer will have "their" repetitions of that integer in the final list. So that would ideally give:
List(1, 2, 2, 3, 3, 3, 4)
I know I can do data.flatten.distinct and get:
List(1, 2, 3, 4)
but that's not what I want and I know there's probably a bit more work to get to the desired result.
I am wondering if there is a good way to achieve the desired result in a functional way in scala.
Try this
val data = List(List(1, 2, 3, 4), List(1, 2, 2, 3, 4), List(1, 2, 3, 3, 3, 4), List(1, 2, 3, 4), List(2, 3, 4))
val map = data.map(_.groupBy(identity)).foldLeft(Map[Int, List[Int]]()) {
case (r, c) => r ++ c.map {
case (k, v) => k -> (if (v.size > r.getOrElse(k, List()).size) v else r(k))
}
}.values.flatten
//> map : Iterable[Int] = List(2, 2, 4, 1, 3, 3, 3)
It does not maintain the ordering. After this you can call to sort this.
Maybe this is cleaner
data.flatMap(_.groupBy(identity)).groupBy(_._1).mapValues(_.sortBy(_._2.size).reverse(0)._2).values.flatten
//> res0: Iterable[Int] = List(2, 2, 4, 1, 3, 3, 3)
I don't quite get it, but you can just order elements
data.flatten.sorted
Which would give you
List(1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4)
if you want them ordered by number of encounters, you can do it like this:
data.flatten.groupBy(k => k).mapValues(_.size).toList.sortBy(_._2).map(_._1)
which would give you
List(1, 4, 2, 3)

How can I sort List[Int] objects?

What I want to do is sort List objects in Scala, not sort the elements in the list. For example If I have two lists of Ints:
val l1 = List(1, 2, 3, 7)
val l2 = List(1, 2, 3, 4, 10)
I want to be able to put them in order where l1 > l2.
I have created a case class that does what I need it to but the problem is that when I use it none of my other methods work. Do I need to implement all the other methods in the class i.e. flatten, sortWith etc.?
My class code looks like this:
class ItemSet(itemSet: List[Int]) extends Ordered[ItemSet] {
val iSet: List[Int] = itemSet
def compare(that: ItemSet) = {
val thisSize = this.iSet.size
val thatSize = that.iSet.size
val hint = List(thisSize, thatSize).min
var result = 0
var loop = 0
val ths = this.iSet.toArray
val tht = that.iSet.toArray
while (loop < hint && result == 0) {
result = ths(loop).compare(tht(loop))
loop += 1
}
if (loop == hint && result == 0 && thisSize != thatSize) {
thisSize.compare(thatSize)
} else
result
}
}
Now if I create an Array of ItemSets I can sort it:
val is1 = new ItemSet(List(1, 2, 5, 8))
val is2 = new ItemSet(List(1, 2, 5, 6))
val is3 = new ItemSet(List(1, 2, 3, 7, 10))
Array(is1, is2, is3).sorted.foreach(i => println(i.iSet))
scala> List(1, 2, 3, 7, 10)
List(1, 2, 5, 6)
List(1, 2, 5, 8)
The two methods that are giving me problems are:
def itemFrequencies(transDB: Array[ItemSet]): Map[Int, Int] = transDB.flatten.groupBy(x => x).mapValues(_.size)
The error I get is:
Expression of type Map[Nothing, Int] doesn't conform to expected type Map[Int, Int]
And for this one:
def sortListAscFreq(transDB: Array[ItemSet], itemFreq: Map[Int, Int]): Array[List[Int]] = {
for (l <- transDB) yield
l.sortWith(itemFreq(_) < itemFreq(_))
}
I get:
Cannot resolve symbol sortWith.
Is there a way I can just extend List[Int] so that I can sort a collection of lists without loosing the functionality of other methods?
The standard library provides a lexicographic ordering for collections of ordered things. You can put it into scope and you're done:
scala> import scala.math.Ordering.Implicits._
import scala.math.Ordering.Implicits._
scala> val is1 = List(1, 2, 5, 8)
is1: List[Int] = List(1, 2, 5, 8)
scala> val is2 = List(1, 2, 5, 6)
is2: List[Int] = List(1, 2, 5, 6)
scala> val is3 = List(1, 2, 3, 7, 10)
is3: List[Int] = List(1, 2, 3, 7, 10)
scala> Array(is1, is2, is3).sorted foreach println
List(1, 2, 3, 7, 10)
List(1, 2, 5, 6)
List(1, 2, 5, 8)
The Ordering type class is often more convenient than Ordered in Scala—it allows you to specify how some existing type should be ordered without having to change its code or create a proxy class that extends Ordered[Whatever], which as you've seen can get messy very quickly.

Sized generators in scalacheck

UserGuide of scalacheck project mentioned sized generators. The explanation code
def matrix[T](g:Gen[T]):Gen[Seq[Seq[T]]] = Gen.sized {size =>
val side = scala.Math.sqrt(size).asInstanceOf[Int] //little change to prevent compile-time exception
Gen.vectorOf(side, Gen.vectorOf(side, g))
}
explained nothing for me. After some exploration I understood that length of generated sequence does not depend on actual size of generator (there is resize method in Gen object that "Creates a resized version of a generator" according to javadoc (maybe that means something different?)).
val g = Gen.choose(1,5)
val g2 = Gen.resize(15, g)
println(matrix(g).sample) // (1)
println(matrix(g2).sample) // (2)
//1,2 produce Seq with same length
Could you explain me what had I missed and give me some examples how you use them in testing code?
The vectorOf (which now is replaced with listOf) generates lists with a size that depends (linearly) on the size parameter that ScalaCheck sets when it evaluates a generator. When ScalaCheck tests a property it will increase this size parameter for each test, resulting in properties that are tested with larger and larger lists (if listOf is used).
If you create a matrix generator by just using the listOf generator in a nested fashion, you will get matrices with a size that depends on the square of the size parameter. Hence when using such a generator in a property you might end up with very large matrices, since ScalaCheck increases the size parameter for each test run. However, if you use the resize generator combinator in the way it is done in the ScalaCheck User Guide, your final matrix size depend linearly on the size parameter, resulting in nicer performance when testing your properties.
You should really not have to use the resize generator combinator very often. If you need to generate lists that are bounded by some specific size, it's much better to do something like the example below instead, since there is no guarantee that the listOf/ containerOf generators really use the size parameter the way you expect.
def genBoundedList(maxSize: Int, g: Gen[T]): Gen[List[T]] = {
Gen.choose(0, maxSize) flatMap { sz => Gen.listOfN(sz, g) }
}
The vectorOf method that you use is deprecated , and you should use the listOf method. This generates a list of random length where the maximum length is limited by the size of the generator. You should therefore resize the generator that
actually generates the actual list if you want control over the maximum elements that are generated:
scala> val g1 = Gen.choose(1,5)
g1: org.scalacheck.Gen[Int] = Gen()
scala> val g2 = Gen.listOf(g1)
g2: org.scalacheck.Gen[List[Int]] = Gen()
scala> g2.sample
res19: Option[List[Int]] = Some(List(4, 4, 4, 4, 2, 4, 2, 3, 5, 1, 1, 1, 4, 4, 1, 1, 4, 5, 5, 4, 3, 3, 4, 1, 3, 2, 2, 4, 3, 4, 3, 3, 4, 3, 2, 3, 1, 1, 3, 2, 5, 1, 5, 5, 1, 5, 5, 5, 5, 3, 2, 3, 1, 4, 3, 1, 4, 2, 1, 3, 4, 4, 1, 4, 1, 1, 4, 2, 1, 2, 4, 4, 2, 1, 5, 3, 5, 3, 4, 2, 1, 4, 3, 2, 1, 1, 1, 4, 3, 2, 2))
scala> val g3 = Gen.resize(10, g2)
g3: java.lang.Object with org.scalacheck.Gen[List[Int]] = Gen()
scala> g3.sample
res0: Option[List[Int]] = Some(List(1))
scala> g3.sample
res1: Option[List[Int]] = Some(List(4, 2))
scala> g3.sample
res2: Option[List[Int]] = Some(List(2, 1, 2, 4, 5, 4, 2, 5, 3))