Scala Iterator.takeWhile is dropping the failed element - scala

val i = (1 to 8).toIterator
val oneToThree = i.takeWhile(_ <= 3).toList
// List(1, 2, 3)
So far so good.
Now I want the iterator to still contain (3, 4, 5, 6, 7, 8), but if I carry on:
val fourToSix = i.takeWhile(_ <= 6).toList
// List(5, 6)
Element 3 has gone missing. I would preferably like fourToSix to be List(4, 5, 6). How can I use takeWhile or some similar operation so that this works?

Note that the documentation on takeWhile states:
Reuse: After calling this method, one should discard the iterator it
was called on, and use only the iterator that was returned. Using the
old iterator is undefined, subject to change, and may result in
changes to the new iterator as well.
So you shouldn't use i, after calling takeWhile on it.
But to achieve what you want you can use the span method:
scala> val i = (1 to 8).iterator
i: Iterator[Int] = non-empty iterator
scala> val (oneToThree, rest) = i.span(_ <= 3)
oneToThree: Iterator[Int] = non-empty iterator
rest: Iterator[Int] = unknown-if-empty iterator
scala> oneToThree.toList
res1: List[Int] = List(1, 2, 3)
scala> val fourToSix = rest.takeWhile(_ <= 6)
fourToSix: Iterator[Int] = non-empty iterator
scala> fourToSix.toList
res2: List[Int] = List(4, 5, 6)

Related

How Immutability is Achieved in Scala Streams?

It might become silly but I have question regarding to Scala Stream evaluation in immutable fashion.
Lets say I have a Stream like this (All lines executed in repl);
val a = Stream(1,2,3,4,5,6,7,8,9,10);
a: scala.collection.immutable.Stream[Int] = Stream(1, ?)
When I run following lines;
a(3);
a
I get ;
scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
My first question is how this immutable structure gets changed ? I mean if did like this (assuming variable 'a' defined as 'var');
a = a(3) I might expect such result.
My other question is when I run following lines;
val a = Stream(1,2,3,4,5,6,7,8,9,10);
a: scala.collection.immutable.Stream[Int] = Stream(1, ?)
val b = a;
b: scala.collection.immutable.Stream[Int] = Stream(1, ?)
b(5);
scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, 5, 6, ?)
a
scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, 5, 6, ?)
As you can see in last part after executing 'a', its seems changed again.
If I try this kind of assignment with List type (as far as I know List is strict version of Stream) and do some transformation like drop,take etc.)
val a = List(1,2,3,4,5)
val b = a;
b.dropRight(1)
variable 'a' and 'b' still is still List(1,2,3,4,5)
So how this happened and what is the point that I'm missing ?
Scala Streams provide memoization - they are like lazy lists, but once elements have been generated, they are stored for future retrieval.
So when you "force" the Stream b to evaluate some of its elements by requesting the element at index 5, the original Stream a (which is the same Stream object) is also forced.
Key point: doing this doesn't modify the stream (it remains immutable), it just changes which elements have been evaluated and are memoized.
Your Stream(1,?) and Stream(1,2,3,4,5,6,?) are the same stream, just evaluated to a different degree:
scala> val a = Stream(1,2,3,4,5,6,7,8,9,10);
a: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> val b = a
scala> a(3)
res9: Int = 4
scala> a
res10: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
scala> b
res11: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
scala> Stream(1,2,3,4,5,6,7,8,9,10) == a
res12: Boolean = true
scala> Stream(1,2,3,4,5,6,7,8,9,10) == b
res13: Boolean = true

Complement method for .last when working with List objects?

Working with Lists in Scala I would like a simple way to get all elements but the last element. Is there a complementary method for .last similar to .head/.tail complement?
I'd rather not dirty up code with something like:
val x: List[String] = List("abc", "def", "ghi")
val allButLast: List[String] = x.reverse.tail.reverse
// List(abc, def)
Thanks.
init selects all elements but the last one.
List API for init.
scala> List(1,2,3,4,5)
res0: List[Int] = List(1, 2, 3, 4, 5)
scala> res0.init
res1: List[Int] = List(1, 2, 3, 4)
The 4 related methods here are head, tail, init, and last.
head and last get the first and final member, whereas
tail and init exclude the first and final members.
scala> val list = (0 to 10).toList
list: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> list.head
res0: Int = 0
scala> list.tail
res1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> list.init
res2: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> list.last
res3: Int = 10
You should also take care, because all 4 of them are unsafe on the empty list and will throw exceptions.
These methods are defined on GenTraversableLike, which List implements.
That's init.
link to Scaladoc: http://www.scala-lang.org/api/2.11.5/index.html#scala.collection.immutable.List#init:Repr
def init: List[A]
Selects all elements except the last.
Also, note that it's defined in GenTraversableLike, so pretty much any Scala collection has this method.
For dropping off any number of items from the end of a list consider dropRight,
val xs = (1 to 5).toList
xs.dropRight(1)
List(1, 2, 3, 4)
xs.dropRight(2)
List(1, 2, 3)
xs.dropRight(10)
List()

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.

How can I use a Scala List as a Stack?

I am trying to solve a hw problem in Scala. A traditional solution require a stack but stacks have not been introduced in the class so far. Only lists have been introduced. My question is how can treat a list as a stack? In other words, how can I mimic pushing and popping elements on a list?
I hope this will show the idea:
scala> val x = List(1,2,3)
x: List[Int] = List(1, 2, 3)
scala> val pushed0 = 0::x
push3: List[Int] = List(0, 1, 2, 3)
scala> val pop0 = pushed0.head
pop3: Int = 0
// it is actually more peek than fair pop
scala> val stackAfterPop = pushed0.tail
stackAfterPop: List[Int] = List(1, 2, 3)
It will actually have much better syntax when you'll be acquainted with pattern matching (next week I guess):
scala> val popped::stack = pushed0
popped: Int = 0
stack: List[Int] = List(1, 2, 3)

Replace element in List with scala

How do you replace an element by index with an immutable List.
E.g.
val list = 1 :: 2 ::3 :: 4 :: List()
list.replace(2, 5)
If you want to replace index 2, then
list.updated(2,5) // Gives 1 :: 2 :: 5 :: 4 :: Nil
If you want to find every place where there's a 2 and put a 5 in instead,
list.map { case 2 => 5; case x => x } // 1 :: 5 :: 3 :: 4 :: Nil
In both cases, you're not really "replacing", you're returning a new list that has a different element(s) at that (those) position(s).
In addition to what has been said before, you can use patch function that replaces sub-sequences of a sequence:
scala> val list = List(1, 2, 3, 4)
list: List[Int] = List(1, 2, 3, 4)
scala> list.patch(2, Seq(5), 1) // replaces one element of the initial sequence
res0: List[Int] = List(1, 2, 5, 4)
scala> list.patch(2, Seq(5), 2) // replaces two elements of the initial sequence
res1: List[Int] = List(1, 2, 5)
scala> list.patch(2, Seq(5), 0) // adds a new element
res2: List[Int] = List(1, 2, 5, 3, 4)
You can use list.updated(2,5) (which is a method on Seq).
It's probably better to use a scala.collection.immutable.Vector for this purpose, becuase updates on Vector take (I think) constant time.
You can use map to generate a new list , like this :
# list
res20: List[Int] = List(1, 2, 3, 4, 4, 5, 4)
# list.map(e => if(e==4) 0 else e)
res21: List[Int] = List(1, 2, 3, 0, 0, 5, 0)
It can also be achieved using patch function as
scala> var l = List(11,20,24,31,35)
l: List[Int] = List(11, 20, 24, 31, 35)
scala> l.patch(2,List(27),1)
res35: List[Int] = List(11, 20, 27, 31, 35)
where 2 is the position where we are looking to add the value, List(27) is the value we are adding to the list and 1 is the number of elements to be replaced from the original list.
If you do a lot of such replacements, it is better to use a muttable class or Array.
following is a simple example of String replacement in scala List, you can do similar for other types of data
scala> val original: List[String] = List("a","b")
original: List[String] = List(a, b)
scala> val replace = original.map(x => if(x.equals("a")) "c" else x)
replace: List[String] = List(c, b)