Scala REPL not printing Range - scala

When I try to print a Range in Scala REPL, how come it doesn't give me the list of numbers.
It displays Range(0 to 10) instead of printing Range(1,2,3,4,5,6,7,8,9,10).
Scala REPL range printout

It looks like the toString function for Range has changed in Scala 2.12.
Testing with 2.12.0:
scala> (1 to 10)
res0: scala.collection.immutable.Range.Inclusive = Range 1 to 10
Testing with 2.11.8:
scala> (0 to 10)
res0: scala.collection.immutable.Range.Inclusive = Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Source code for 2.12:
override def toString = {
val preposition = if (isInclusive) "to" else "until"
val stepped = if (step == 1) "" else s" by $step"
val prefix = if (isEmpty) "empty " else if (!isExact) "inexact " else ""
s"${prefix}Range $start $preposition $end$stepped"
}
Source code for 2.11:
override def toString() = {
val endStr =
if (numRangeElements > Range.MAX_PRINT || (!isEmpty && numRangeElements < 0)) ", ... )" else ")"
take(Range.MAX_PRINT).mkString("Range(", ", ", endStr)
}

An easy solution, when you're lost with the bounds of your Range and want to inspect its actual individual elements, consists in transforming it as a List:
scala> (0 until 10)
res0: scala.collection.immutable.Range = Range 0 until 10
scala> (0 until 10).toList
res1: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

Related

Scala: On strange behavior of `foldLeft`

Define:
val a = List(1, 2, 3, 4, 5, 6, 7)
Consider the following line with foldLeft:
a.foldLeft(""){case (num, sum) => sum + (num.toString + "-")}
My expectation was that the program is going to do:
((((( "7-" + "6-" ) + "5-" ) + "4-" ) + "3-" ) + "2-" ) + "1-"
which is 7-6-5-4-3-2-1-
But what I get is: 7654321-------. Why is this the case?
You mixed up the parameters to foldLeft. Check the documentation for List.foldLeft. Note that the z "zero" value has the same type as the second parameter in the function argument, not the first.
This should work closer to expected:
a.foldLeft(""){case (sum, num) => sum + (num.toString + "-")}
// res0: String = 1-2-3-4-5-6-7-
However, if you want the numbers in reverse-order, then you might want to use foldRight. Maybe this is actually what you were going for in the first place (notice that the arguments num and sum are in the same order you gave):
a.foldRight(""){case (num, sum) => sum + (num.toString + "-")}
// res1: String = 7-6-5-4-3-2-1-
From your expectation, I expect you expected foldRight behavior:
scala> val a = List(1, 2, 3, 4, 5, 6, 7)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
scala> a.foldRight(""){case (num, sum) => sum + (num.toString + "-")}
res0: String = 7-6-5-4-3-2-1-

Group list of numbers into groups based on the range from the lowest number

Assuming there the list of numbers and a range value, I want to group them into groups, in which the item in each group is within the range from the lowest number, and sort them.
For example, I have a list val l = List(1,2,3,4,5,6,7,8,9,10) and the range val range = 2. Then, I'm looking for a way to output the following result: result = List(List(1,2,3), List(4,5,6), List(7,8,9), List(10)). Which means if range = 0 then only identical numbers are in the same group.
At the moment, I use the following method
val minVal = l.min
val range1 = (minVal + range).toDouble
val groups = l.foldLeft(Map[Int, List[Int]]())((result, num) => {
val numRange = math.ceil(num / range1).toInt
if (result.contains(numRange)) {
result.updated(numRange, num :: result(numRange))
} else {
result.updated(numRange, List(num))
}
})
groups.keys.toList.sortBy(k => k).map(groups(_))
It works in most cases except when range = 0 and slowestNum != 1. E.g. for the list val l = List(2,3,4,5,6,7,8,9,10) and the range val range = 2, the result is List(List(2), List(4, 3), List(6, 5), List(8, 7), List(10, 9)).
So, I wonder if there is any other way to solve this problem.
Why complicate?
def coll(l: List[Int], range: Int): List[List[Int]] =
if (l.isEmpty) Nil else {
val (b, a) = l.span((l.head - range to l.head + range).contains)
b :: coll(a, range)
}
So, this algorithm collects numbers into a group until the number are in the plus/minus range.
val list = List(7,4,1,9,10,20,50,52,30)
coll(list, 3)
res6: List[List[Int]] = List(List(7, 4), List(1), List(9, 10), List(20), List(50, 52), List(30))
If you want each group by itself sorted, then call res6.map(_.sorted).
I would personally do something like this:
val l = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val range = 2
val result = l.sorted.foldLeft(List[List[Int]]()) {
(cur, x) =>
if ((cur nonEmpty) && x - cur.head.last <= range) (x :: cur.head) :: cur.tail
else List(x) :: cur
}
although there may be some clever and neat ways. Of course, you can always do if you want the result ordered:
val ret = result.reverse.map(_.reverse)
Hope it helped!
Try something like this
val groupedList = l.map(i => l.filter(s => s >= i && s - i <= range))
groupedList.foldLeft(List(groupedList.head)) {
case (r, c) => if (r.last.last < c.head) r ++ List(c) else r
}
For range 2
val l = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val range = 2
val groupedList = l.map(i => l.filter(s => s >= i && s - i <= range))
groupedList.foldLeft(List(groupedList.head)) {
case (r, c) => if (r.last.last < c.head) r ++ List(c) else r
}
//> res0: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9), List(10))
For range 0
val l = List(1,1,1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val range = 0
val groupedList = l.map(i => l.filter(s => s >= i && s - i <= range))
groupedList.foldLeft(List(groupedList.head)) {
case (r, c) => if (r.last.last < c.head) r ++ List(c) else r
}
//> res0: List[List[Int]] = List(List(1, 1, 1), List(2), List(3), List(4), List(5), List(6), List(7), List(8), List(9), List(10))

Can we call method having more than one arguments with list.map?

I was trying to perform multiply operation on list in Scala like:
val list = List(1,2,3,4,5)
list.map(_*2)
res0: List[Int] = List(2, 4, 6, 8, 10) // Output
Now, I have created a separate method for the multiply operation like:
val list = List(1,2,3,4,5)
def multiplyListContents(x: Int) = {
x * 2
}
list.map(multiplyListContents)
res1: List[Int] = List(2, 4, 6, 8, 10) // Output
Now I want to pass custom multiplier instead of using default multiplier 2 like:
val list = List(1,2,3,4,5)
val multiplier = 3
def multiplyListContents(x: Int, multiplier: Int) = {
x * multiplier
}
list.map(multiplyListContents(multiplier))
res1: List[Int] = List(3, 6, 9, 12, 15) // Output should be this
Any idea how to do this?
scala> list.map(multiplyListContents(_, multiplier))
res0: List[Int] = List(3, 6, 9, 12, 15)
This translates to list.map(x => multiplyListContents(x, multiplier)).
(see scala placeholder syntax for more information).

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.

Scala syntax problem

The following code can be compiled
def isEven(a:Int)=
if (a%2==0) true else false
def main(args: Array[String]) {
List(1, 10) filter isEven foreach println
but if I change to following ( List(1,10) --> List(1 to 10))
def isEven(a:Int)=
if (a%2==0) true else false
def main(args: Array[String]) {
List(1 to 10) filter isEven foreach println
}
What's difference between List(1,10) and List(1 to 10) ?
List(1, 2) is simply a list with two Int elements: 1 and 2. The expression 1 to 10 creates a Range instance, so List(1 to 10) is a list with one element: a Range.
List(1, 10) is a List[Int] whereas List(1 to 10) is a List[Range]. Observe the types in the following REPL session:
scala> 1 to 10
res3: scala.collection.immutable.Range.Inclusive with scala.collection.immutable.Range.ByOne = Range(1, 2, 3, 4, 5, 6, 7
, 8, 9, 10)
scala> List(1 to 10)
res4: List[scala.collection.immutable.Range.Inclusive with scala.collection.immutable.Range.ByOne] = List(Range(1, 2, 3,
4, 5, 6, 7, 8, 9, 10))
scala> List(1, 10)
res5: List[Int] = List(1, 10)
missingfaktor is right, so this is just an addition.
If you want a List[Int] with numbers from 1 to 10, you can write
List(1 to 10:_*)
or
1 to 10 toList