val list = List()
for(i <- 1 to 10){
list: i
}
println(list)
This ends up giving me an empty list although it should be filled with numbers from 1 to 10? I have a theory that it creates a new list each time due to the ":" operator but I am not entirely sure. I have solved the issue using a ListBuffer instead but I want to learn how to approach such a problem using immutable lists instead. Thank you.
CodePudding user response:
There is no single functional solution to this class of problem, but here are some options.
For the simple case in the question, you can do this
List.range(1,11) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
If you want to calculate a different value for each element based on index, use tabulate:
List.tabulate(10)(x => x*3) // List(0, 3, 6, 9, 12, 15, 18, 21, 24, 27)
(You can pass a function if the logic is more complicated than this)
If you are building a list but are not sure whether you need every element, use Option and then flatten:
def genValue(i: Int): Option[Int] = ???
List.tabulate(10)(genValue).flatten
This will discard any values where genValue returns None and extract the Int where it returns Some(???).
If each operation may return a different number of elements, use List then flatten:
def genValue(i: Int): List[Int] = ???
List.tabulate(10)(genValue).flatten
This will take all the elements from all the List values returned by genValue and put them into a single List[Int].
If the length of the List is not known in advance then the best solution is likely to be a recursive function. While this may seem daunting to start with, it is worth learning how to use them as they are often the cleanest way of solving a problem.
CodePudding user response:
You cannot add an element (that is mutate the list) to an immutable list. You are right when you say:
I have a theory that it creates a new list each time
as a first step consider
var list = List.empty[Int]
for(i <- 1 to 10) {
list = list : i
}
println(list)
note that list is now a variable so that we can reassign value, but the list is still an immutable object. Infact for each iteratin we reassign to the variable list a new list with an element appended If you don't like the use of a variable you could use a fold operation, which is not much different from the for above, it still construct partial lists adding element one by one
val result = (1 to 10).foldLeft(List.empty[Int]){ (partial_list, item) =>
partial_list : item
}
println(result)
CodePudding user response:
Here is the simplified signature of : :
def : (elem: B): List[B]
It returns a new List with elem so it does not alter the current list.
To make this work switch to a ListBuffer i.e. something mutable:
import scala.collection.mutable.ListBuffer
val buffer = ListBuffer.empty[Int]
for(i <- 1 to 10) {
buffer = i
}
println(buffer)
If you want to keep the immutable List you could accumulate with fold:
val list = List.empty[Int]
(1 to 10)
.foldLeft(list) { (acc, value) => acc : value }
