2

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?

2
  • 1
    Maybe instead of downvoting, SO should have an option to flag, "Did not take Coursera." Commented Aug 14, 2015 at 23:43
  • The return type of foreach is Unit, so you don't end up with anything. You probably want map? Commented Aug 15, 2015 at 0:31

8 Answers 8

1

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))
Sign up to request clarification or add additional context in comments.

Comments

1

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.

Comments

1

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))

16 Comments

Correct answer because it works, bad answer because it shows a bad practice and an anti-pattern
Sorry, @Dici, but every function that wants to build a collection has a choice of whether to use a mutable builder imperatively or using an immutable collection monadically. This is a point driven home over and again, so I make it again. The question is how to build them, not how to use map, etc.
So what is the advantage of your snippet over the idiomatic xs ::: (1 to 10) ?
@Dici For example, Odersky just complained in his talk on dotty that everyone changed his imperative loops to functional stuff in scalac and it all got slow.
@Dici I only know what they tell me. I don't disagree w/u about prefer functional, but imperative with local mutables has its place & also easy for Java folks to grok. Until they know better. As a ref only, youtube.com/…
|
1

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.

Comments

1

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))

Comments

0

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) 

Comments

0
// 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

Comments

-2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.