Scala Iterator with Map and For - scala

Given:
val list = List("one","two","three")
val it = list.toIterator
I can run:
list map ("_" +) -> List(_one, _two, _three)
for (i <- list) yield("_" + i) -> List(_one, _two, _three)
If I run the same on the iterator I get:
it map ("_" + ) -> Iterator[java.lang.String] = empty iterator
for (i <- it) yield("_" + i) -> Iterator[java.lang.String] = empty iterator
Shouldn't I get back another (non-empty) Iterator[String] after I run map/for on it?

scala> def ints(n: Int): Stream[Int] = n #:: ints(n + 1)
ints: (n: Int)Stream[Int]
scala> val list = List("one","two","three")
list: List[java.lang.String] = List(one, two, three)
scala> val it = list.toIterator
it: Iterator[java.lang.String] = non-empty iterator
scala> it map ("_" + )
res24: Iterator[java.lang.String] = non-empty iterator
scala> it map ("_" + )
res25: Iterator[java.lang.String] = non-empty iterator
scala> for (i <- it) yield("_" + i)
res26: Iterator[java.lang.String] = non-empty iterator
Maybe you used your iterator?
scala> res26.foreach{println}
_one
_two
_three
scala> res26
res28: Iterator[java.lang.String] = empty iterator
Since iterators are stateful and not resettable, once you used it, it is empty and can't be used again.
Instead, you can use views:
scala> val v = list.view
v: java.lang.Object with scala.collection.SeqView[java.lang.String,List[java.lang.String]] = SeqView(one, two, three)
scala> v map ("_" + )
res29: scala.collection.SeqView[java.lang.String,Seq[_]] = SeqViewM(...)
scala> for (i <- v) yield("_" + i)
res30: scala.collection.SeqView[java.lang.String,Seq[_]] = SeqViewM(...)
scala> res29.foreach{println}
_one
_two
_three
scala> res29
res32: scala.collection.SeqView[java.lang.String,Seq[_]] = SeqViewM(...)
scala> res29.foreach{println}
_one
_two
_three

See Iterators.
There's an important difference between the foreach method on iterators and the same method on traversable collections: When called to an iterator, foreach will leave the iterator at its end when it is done. So calling next again on the same iterator will fail with a NoSuchElementException. By contrast, when called on on a collection, foreach leaves the number of elements in the collection unchanged (unless the passed function adds to removes elements, but this is discouraged, because it may lead to surprising results).
...
As you can see, after the call to it.map, the it iterator has advanced to its end.

Related

Appending to Seq in Scala

The following code is supposed to append to a Seq, but it prints an empty list, what's wrong here?
object AppendToSeq extends App{
val x = Seq[Int]()
x :+ 1
x :+ 2
println(x)
}
the value x created is an immutable Sequence and the method :+ defined on the immutable sequence return a new Seq object.
so your code should have x has a var (a mutable variable) and it should have its value re-assigned after each append (:+) operation as shown below.
scala> var x = Seq[Int]()
x: Seq[Int] = List()
scala> x = x :+ 1
x: Seq[Int] = List(1)
scala> x = x :+ 2
x: Seq[Int] = List(1, 2)
scala> x
res2: Seq[Int] = List(1, 2)
x :+ 1 creates a new Seq by appending 1 to the existing Seq, x, but the new Seq isn't saved anywhere, i.e. it isn't assigned to any variable, so it's just thrown away.
If you want to modify an existing Seq you can make the variable a var instead of a val. Then when you create a new Seq you can save it under the same name.
scala> var x = Seq[Int]()
x: Seq[Int] = List()
scala> x = x :+ 7
x: Seq[Int] = List(7)

Define a 2d list and append lists to it in a for loop, scala

I want to define a 2d list before a for loop and afterwards I want to append to it 1d lists in a for loop, like so:
var 2dEmptyList: listOf<List<String>>
for (element<-elements){
///do some stuff
2dEmptyList.plusAssign(1dlist)
}
The code above does not work. But I can't seem to find a solution for this and it is so simple!
scala> val elements = List("a", "b", "c")
elements: List[String] = List(a, b, c)
scala> val twoDimenstionalList: List[List[String]] = List.empty[List[String]]
twoDimenstionalList: List[List[String]] = List()
scala> val res = for(element <- elements) yield twoDimenstionalList ::: List(element)
res: List[List[java.io.Serializable]] = List(List(a), List(b), List(c))
Better still:
scala> twoDimenstionalList ::: elements.map(List(_))
res8: List[List[String]] = List(List(a), List(b), List(c))
If you want 2dEmptyList be mutable, please consider using scala.collection.mutable.ListBuffer:
scala> val ll = scala.collection.mutable.ListBuffer.empty[List[String]]
ll: scala.collection.mutable.ListBuffer[List[String]] = ListBuffer()
scala> ll += List("Hello")
res7: ll.type = ListBuffer(List(Hello))
scala> ll += List("How", "are", "you?")
res8: ll.type = ListBuffer(List(Hello), List(How, are, you?))

Scala Iteratively build lists

As a Scala beginner I am still struggling working with immutable lists. All I am trying to do append elements to my list. Here's an example of what I am trying to do.
val list = Seq()::Nil
val listOfInts = List(1,2,3)
listOfInts.foreach {case x=>
list::List(x)
}
expecting that I would end up with a list of lists: List(List(1),List(2),List(3))
Coming from java I am used to just using list.add(new ArrayList(i)) to get the same result. Am I way off here?
Since the List is immutable you can not modify the List in place.
To construct a List of 1 item Lists from a List, you can map over the List. The difference between forEach and map is that forEach returns nothing, i.e. Unit, while map returns a List from the returns of some function.
scala> def makeSingleList(j:Int):List[Int] = List(j)
makeSingleList: (j: Int)List[Int]
scala> listOfInts.map(makeSingleList)
res1: List[List[Int]] = List(List(1), List(2), List(3))
Below is copy and pasted from the Scala REPL with added print statement to see what is happening:
scala> val list = Seq()::Nil
list: List[Seq[Nothing]] = List(List())
scala> val listOfInts = List(1,2,3)
listOfInts: List[Int] = List(1, 2, 3)
scala> listOfInts.foreach { case x=>
| println(list::List(x))
| }
List(List(List()), 1)
List(List(List()), 2)
List(List(List()), 3)
During the first iteration of the foreach loop, you are actually taking the first element of listOfInts (which is 1), putting that in a new list (which is List(1)), and then adding the new element list (which is List(List()) ) to the beginning of List(1). This is why it prints out List(List(List()), 1).
Since your list and listOfInts are both immutable, you can't change them. All you can do is perform something on them, and then return a new list with the change. In your case list::List(x) inside the loop actually doesnt do anything you can see unless you print it out.
There are tutorials on the documentation page.
There is a blurb for ListBuffer, if you swing that way.
Otherwise,
scala> var xs = List.empty[List[Int]]
xs: List[List[Int]] = List()
scala> (1 to 10) foreach (i => xs = xs :+ List(i))
scala> xs
res9: List[List[Int]] = List(List(1), List(2), List(3), List(4), List(5), List(6), List(7), List(8), List(9), List(10))
You have a choice of using a mutable builder like ListBuffer or a local var and returning the collection you build.
In the functional world, you often build by prepending and then reverse:
scala> var xs = List.empty[List[Int]]
xs: List[List[Int]] = List()
scala> (1 to 10) foreach (i => xs = List(i) :: xs)
scala> xs.reverse
res11: List[List[Int]] = List(List(1), List(2), List(3), List(4), List(5), List(6), List(7), List(8), List(9), List(10))
Given val listOfInts = List(1,2,3), and you want the final result as List(List(1),List(2),List(3)).
Another nice trick I can think of is sliding(Groups elements in fixed size blocks by passing a "sliding window" over them)
scala> val listOfInts = List(1,2,3)
listOfInts: List[Int] = List(1, 2, 3)
scala> listOfInts.sliding(1)
res6: Iterator[List[Int]] = non-empty iterator
scala> listOfInts.sliding(1).toList
res7: List[List[Int]] = List(List(1), List(2), List(3))
// If pass 2 in sliding, it will be like
scala> listOfInts.sliding(2).toList
res8: List[List[Int]] = List(List(1, 2), List(2, 3))
For more about the sliding, you can have a read about sliding in scala.collection.IterableLike.
You can simply map over this list to create a List of Lists.
It maintains Immutability and functional approach.
scala> List(1,2,3).map(List(_))
res0: List[List[Int]] = List(List(1), List(2), List(3))
Or you, can also use Tail Recursion :
#annotation.tailrec
def f(l:List[Int],res:List[List[Int]]=Nil) :List[List[Int]] = {
if(l.isEmpty) res else f(l.tail,res :+ List(l.head))
}
scala> f(List(1,2,3))
res1: List[List[Int]] = List(List(1), List(2), List(3))
In scala you have two (three, as #som-snytt has shown) options -- opt for a mutable collection (like Buffer):
scala> val xs = collection.mutable.Buffer(1)
// xs: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1)
scala> xs += 2
// res10: xs.type = ArrayBuffer(1, 2)
scala> xs += 3
// res11: xs.type = ArrayBuffer(1, 2, 3)
As you can see, it works just like you would work with lists in Java. The other option you have, and in fact it's highly encouraged, is to opt to processing list functionally, that's it, you take some function and apply it to each and every element of collection:
scala> val ys = List(1,2,3,4).map(x => x + 1)
// ys: List[Int] = List(2, 3, 4, 5)
scala> def isEven(x: Int) = x % 2 == 0
// isEven: (x: Int)Boolean
scala> val zs = List(1,2,3,4).map(x => x * 10).filter(isEven)
// zs: List[Int] = List(10, 20, 30, 40)
// input: List(1,2,3)
// expected output: List(List(1), List(2), List(3))
val myList: List[Int] = List(1,2,3)
val currentResult = List()
def buildIteratively(input: List[Int], currentOutput: List[List[Int]]): List[List[Int]] = input match {
case Nil => currentOutput
case x::xs => buildIteratively(xs, List(x) :: currentOutput)
}
val result = buildIteratively(myList, currentResult).reverse
You say in your question that the list is immutable, so you do are aware that you cannot mutate it ! All operations on Scala lists return a new list. By the way, even in Java using a foreach to populate a collection is considered a bad practice. The Scala idiom for your use-case is :
list ::: listOfInts
Shorter, clearer, more functional, more idiomatic and easier to reason about (mutability make things more "complicated" especially when writing lambda expressions because it breaks the semantic of a pure function). There is no good reason to give you a different answer.
If you want mutability, probably for performance purposes, use a mutable collection such as ArrayBuffer.

How to use an autoincrement index in for comprehension in Scala

Is it possible to use an autoincrement counter in for comprehensions in Scala?
something like
for (element <- elements; val counter = counter+1) yield NewElement(element, counter)
I believe, that you are looking for zipWithIndex method available on List and other collections. Here is small example of it's usage:
scala> val list = List("a", "b", "c")
list: List[java.lang.String] = List(a, b, c)
scala> list.zipWithIndex
res0: List[(java.lang.String, Int)] = List((a,0), (b,1), (c,2))
scala> list.zipWithIndex.map{case (elem, idx) => elem + " with index " + idx}
res1: List[java.lang.String] = List(a with index 0, b with index 1, c with index 2)
scala> for ((elem, idx) <- list.zipWithIndex) yield elem + " with index " + idx
res2: List[java.lang.String] = List(a with index 0, b with index 1, c with index 2)
A for comprehension is not like a for loop in that the terms are evaluated for each previous term. As an example, look at the results below. I don't think that's what you are looking for:
scala> val elements = List("a", "b", "c", "d")
elements: List[java.lang.String] = List(a, b, c, d)
scala> for (e <- elements; i <- 0 until elements.length) yield (e, i)
res2: List[(java.lang.String, Int)] = List((a,0), (a,1), (a,2), (a,3), (b,0), (b,1), (b,2), (b,3), (c,0), (c,1), (c,2), (c,3), (d,0), (d,1), (d,2), (d,3))
tenshi's answer is probably more on track with your desired result, but I hope this counterexample is useful.

Make a recursive Stream from just 1 element?

I've made a Stream for Gray Codes using recursion as follows:
val gray: Stream[List[String]] = {
List("") #:: List("0", "1") #:: gray.tail.map {gnext}
}
where
val gnext = (i:List[String]) => i.map {"0" + _} ::: i.reverse.map {"1" + _}
so that, for example
scala> gray(2)
res17: List[String] = List(00, 01, 11, 10)
I don't really need the List("0", "1") in the definition, because it can be produced from element 0:
scala> gnext(List(""))
res18: List[java.lang.String] = List(0, 1)
So is there a way / pattern that can be used to produce a Stream from just the first element?
val gray: Stream[List[String]] = List("") #:: gray.map {gnext}
Or, alternatively,
val gray = Stream.iterate(List(""))(gnext)