tags:

views:

238

answers:

6

Hi,

I wanted to add items dynamically into an array. But it seems Scala Arrays & Lists doesn't provide any methods for adding items dynamically due to the immutable nature.

So i decided to use List data type to make use of this :: method to achieve this. My code look like this

var outList = List(Nil)
val strArray = Array("ram","sam","bam")

for (str<-strArray)
     outList = str :: outList

Though it works in some way, the problem is the new strings are pre-appended into the list. But the ideal requirement is order of the data. Yeah i know what you are thinking, you can reverse the final result list to get the original order. But the problem is its a huge array. And i believe its not a solution though it solves the problem. I believe there should be a simple way to solve this..

And my reason to hacking scala is to learn the functional way of coding. Having var (mutable type) and populating the list on the fly seems to me is not a functional way of solving things.

please advice me..

Update:

ideally i want to achieve something like this in scala (below the c# code)

List<int> ls = new List<int>();    
for (int i = 0; i < 100; i++)
      ls.Add(i);

Cheers

+2  A: 

Okay, there are a few things to clear up.

This is wrong, you're make a one element list, containing an empty list:

scala> var outList = List(Nil) 
outList: List[object Nil] = List(List())

Nil is the empty list:

scala> var outList: List[String] = Nil
outList: List[String] = List()

Or, if you prefer:

scala> var outList = List[String]() 
outList: List[String] = List()

Without more context, it's hard to know what you mean by 'dynamically'. Your example code would be better written as:

scala> val strArray = Array("ram","sam","bam")
strArray: Array[java.lang.String] = Array(ram, sam, bam)

scala> strArray toList
res0: List[java.lang.String] = List(ram, sam, bam)

If you want a mutable collection that can grow and efficiently handle prepend, append, and insert operations, you could use scala.mutable.Buffer.

retronym
@retronym please add formatting to the 2 examples in the middle.
olle kullberg
@retronym, dynamically in the sense "i want to populate the list on the fly". the size is unknown. It could be anything based on the incoming data.. i have updated my question for more clarity
Ramesh Vel
+2  A: 

Going after retronym's answer:

If you still want to use list there are a few ways to prepend an item to the list. What you can do is (yes the top part is still wrong):

scala> var outList : List[String] = Nil
outList: List[String] = List()

scala> val strArray = Array("a","b","c")
strArray: Array[java.lang.String] = Array(a, b, c)

scala> for(s <- strArray)      
     | outList = outList :+ s

scala> outList
res2: List[String] = List(a, b, c)

Note the :+ operator. If you rather append, you'd use s +: outList.

Now who says programming in Scala isn't fun? ;)

P.S. Maybe the reason why you'd want to make them immutable is the speed. Handling large data will be more efficient with immutable data types. Am I right?

the_great_monkey
Note that `for(s <- strArray) { outList = outList :+ s }` takes quadratic time.
Alexey Romanov
Ahh, bugger! Really? What about outList ::: s? Do you have any reference of the complexity of scala functions? I tried googling didn't find anything.From http://stackoverflow.com/questions/1241166/preferred-way-to-create-a-scala-list I think the general consensus is to prepend and reverse.
the_great_monkey
Same. `List` is an immutable linked list, so appending 1 element to one -- whatever method you use -- _has to_ take linear time (since you have to copy all of its elements), so this loop takes quadratic time. Appending to `ListBuffer` and calling `toList` is better than prepending and reversing, but prepending and reversing is _much_ better than appending to a `List`.
Alexey Romanov
+7  A: 

But it seems Scala Arrays & Lists doesn't provide any methods for adding items dynamically due to the immutable nature.

Well, no. Scala Arrays are just Java arrays, so they are mutable:

val arr = Array(1,2)

arr(0) = 3 // arr == Array(3, 2)

But just as Java (and C/C++/C#/etc.) arrays, you can't change the size of an array.

So you need another collection, which is backed by an array, but does allow resizing. A suitable collection in Scala is scala.collection.mutable.ArrayBuffer, java.util.ArrayList in Java, etc.

If you want to get a List instead of an Array in the end, use scala.collection.mutable.ListBuffer instead.

Alexey Romanov
@Alexey, thanks.. "ListBuffer" is the one i wanted.. :)
Ramesh Vel
+3  A: 

If you want to use a mutable Buffer, as retronym mentioned. It looks like this:

scala> var outList = scala.collection.mutable.Buffer[String]()
outList: scala.collection.mutable.Buffer[String] = ArrayBuffer()

scala> for(str<-strArray) outList += str                          

scala> outList
res10: scala.collection.mutable.ListBuffer[String] = ListBuffer(ram, sam, bam)

Anyway, perhaps it is better to directly do the things you want to do with the strArray. E.g:

strArray map(_.toUpperCase) foreach(println)
michael.kebe
+3  A: 

If you want to work with immutable structures, you can use the ++ method:

scala> val orgList = List(1,2,3)
orgList: List[Int] = List(1, 2, 3)

scala> val list2Add = List(4,5,6)
list2Add: List[Int] = List(4, 5, 6)

scala> val newList = orgList ++ list2Add
newList: List[Int] = List(1, 2, 3, 4, 5, 6)

If you want to do more work on the elements than just adding them you can use higher order functions:

val newList = orgList ++ list2Add.map(_ * 2)
newList: List[Int] = List(1, 2, 3, 8, 10, 12)

Or with a for loop:

val newList = orgList ++ {for(x <- list2Add) yield 2*x}

Or you could create some recursive loop:

def addAll(toList: List[Int], fromList: List[Int]): List[Int] =
  fromList match {
    case x :: tail => addAll(2*x :: toList, tail)
    case Nil => toList
  }

val newList = addAll(orgList, list2Add )

but in this case the ordering of the added elements will be in reversed:

List(12, 10, 8, 1, 2, 3)

If you want performance when working with lists, it is better to reverse the result than try to add new elements in the end. Adding elements in the end to a list is nooot good :-)

olle kullberg
@Olle, thats not requirement... i want to populate the list on the fly". the size is unknown. It could be anything based on the incoming data.. i have updated my question for more clarity
Ramesh Vel
A: 

If you are looking to create a new collection, you can use the yield key word:

val outlist = for(i <- 0 to 100) yield i

Or:

val arrList = "Some" :: "Input" :: "List" :: Nil
val outlist = for ( i <- arrList ) yield i

Technically, outlist is a Seq in both of the above examples so you may need to call the toList method on it if you need some of List's methods.

Aaron
You don't even need to say `for(i <- 0 to 100) yield i`. You can just say `(0 to 100)` and, if desired, convert it to a different collection with the `.toList` method or such.
MJP