Scala array understanding? - scala

I have tried below array example in my scala console.Declared immutable array, tried to change the array index values.Immutable should not allow modifying the values. I don't understand whats happening .can anyone explain, please.
val numbers=Array(1,2,3)
numbers(0)=5
print numbers
res1: Array[Int] = Array(5, 2, 3)
Thanks!

Declaring something as a val does not make it immutable. It merely prevents reassignment. For example, the following code would not compile:
val numbers = Array(1, 2, 3)
numbers = Array(5, 2, 3)
Notice that what changes in the above code is not something about the array object's internal state: what changes is the array that the name numbers references. At the first line, the name numbers refers to the array Array(1, 2, 3), but in the second line we try reassign the name numbers to the array Array(5, 2, 3) (which the compiler won't allow, since the name numbers is declared using val).
In contrast, the below code is allowed:
val numbers = Array(1, 2, 3)
numbers(0) = 5
In this code, the name numbers still points to the same array, but it's the internal state of the array that has changed. Using the val keyword for the name of an object cannot prevent that object's internal state from changing, the val keyword can only prevent the name from being reassigned to some other object.

You did not declare an immutable array. Array in Scala is mutable.
Where you might be confused is what exactly val vs var means. val does not make an object immutable, it makes the reference immutable so you can't reassign a different array to your variable, but you can still modify the contents since it is a mutable object.
If you want immutability you need to use val together with an immutable object like Vector or List.

Maybe your understanding of scala Array is not right.
Please pay attention to the following principle!
Arrays preserve order, can contain duplicates, and are mutable.
scala> val numbers = Array(1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
numbers: Array[Int] = Array(1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
scala> numbers(3) = 10
Lists preserve order, can contain duplicates, and are immutable.
scala> val numbers = List(1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
numbers: List[Int] = List(1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
scala> numbers(3) = 10
<console>:9: error: value update is not a member of List[Int]
numbers(3) = 10

Related

Why are Sets of up to 4 elements ordered but larger ones are not?

Given
val xs1 = Set(3, 2, 1, 4, 5, 6, 7)
val ys1 = Set(7, 2, 1, 4, 5, 6, 3)
xs1 and ys1 both result in scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 7, 3, 4)
but smaller sets bellow
val xt1 = Set(1, 2, 3)
val yt1 = Set(3, 2, 1)
produce
xt1: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
yt1: scala.collection.immutable.Set[Int] = Set(3, 2, 1)
Why are former not ordered whilst latter seem to be ordered?
Difference in behaviour is due to optimisations for Sets of up to 4 elements
The default implementation of an immutable set uses a representation
that adapts to the number of elements of the set. An empty set is
represented by just a singleton object. Sets of sizes up to four are
represented by a single object that stores all elements as fields.
Beyond that size, immutable sets are implemented as Compressed
Hash-Array Mapped Prefix-tree.
similarly explained by Ben James:
Set is also a companion object* with an apply** method. When you call
Set(...), you're calling this factory method and getting a return
value which is some kind of Set. It might be a HashSet, but could be
some other implementation. According to 2, the default implementation
for an immutable set has special representation for empty set and sets
size up to 4. Immutable sets size 5 and above and mutable sets all use
hashSet.
Since size of Set(3, 2, 1, 4, 5, 6, 7) is greater than 4, then its concrete implementation is HashSet
Set(3, 2, 1, 4, 5, 6, 7).getClass
class scala.collection.immutable.HashSet
which does not guarantee insertion order. On the other hand, concrete implementation of Set(1, 2, 3) is dedicated class Set3
Set(1,2,3).getClass
class scala.collection.immutable.Set$Set3
which stores the three elements in corresponding three fields
final class Set3[A] private[collection] (elem1: A, elem2: A, elem3: A) extends AbstractSet[A] ...

How to pick up how to get elements from List in Scala?

I have a list of elements List(1,2,3,4,5,6) which I hope to get a few elements from it to form a new List to List(2,4,5,6).
How should I go about it? Thanks!
scala collections can be mapped or filtered. In your case you simply can filter with the function you want.
eg. in scala REPL.
filter elements which are greater than or equals to 2.
scala> List(1,2,3,4,5,6).filter(_>=2)
res3: List[Int] = List(2, 3, 4, 5, 6)
or to filter all elements which are not 1 and 3,
scala> List(1,2,3,4,5,6).filter(element => (element!=1 && element!=3))
res6: List[Int] = List(2, 4, 5, 6)
Also read
https://twitter.github.io/scala_school/collections.html#filter
http://alvinalexander.com/scala/how-to-use-filter-method-scala-collections-cookbook

How would I unit test a method that internally shuffles an array randomly

I have a method that looks like this:
def compute[T](l: List[T]): List[T] = {
val shuffled = util.Random.shuffle(l)
// do some more computations
}
I wanted to seed the random number generator for my unit tests so that I don't have to break down my method into two methods and test only the computation, since this is the method that will be used externally. Is this possible to do in ScalaTest?
I don't have much background in ScalaTest, but if you call setSeed(seed: Long): Unit then you'll always get the same shuffle for any given seed value.
scala> util.Random.shuffle(Seq(1,2,3,4,5,6,7,8,9,0))
res0: Seq[Int] = List(6, 0, 8, 5, 4, 7, 2, 3, 1, 9)
scala> util.Random.setSeed(57L)
scala> util.Random.shuffle(Seq(1,2,3,4,5,6,7,8,9,0))
res1: Seq[Int] = List(5, 3, 2, 0, 6, 8, 7, 4, 1, 9)
scala> util.Random.setSeed(57L)
scala> util.Random.shuffle(Seq(1,2,3,4,5,6,7,8,9,0))
res2: Seq[Int] = List(5, 3, 2, 0, 6, 8, 7, 4, 1, 9)
how would you test the method that depends on current time? or database state? or response from google? or sleeping for some time?
generally when you test any code that depends on some external state (time, other system, or in your case: entropy / seed), you refactor that code and extract the dependency. one way, as #jwvh said is to extract seed. but imho, you should extract the whole transformation
therefore you should create a method that receives the shuffled array and test that method

Assigning one value to many elements of an array in Scala

I have some experience with R language and now I wanted to try Scala language. In R language I can assign one value to many elements of a vector, e.g.
(xs <- 1:10)
#[1] 1 2 3 4 5 6 7 8 9 10
k <- 3
xs[1:k] <- xs[k+1]
xs
# 4 4 4 4 5 6 7 8 9 10
It assigns value of k+1 element to all elements of indices from 1 to k. Is it also possible to do it without a loop in Scala (I mean Array in Scale)? I know there is slice method, but it only returns values of an Array, one cannot modify elements of the Array using this method.
What is even more, should I use Array or ArrayBuffer if I only want to change values of elements and I do not want to add/remove elements from a collection?
Check out the java.util.Arrays.fill methods.
scala> val xs = (1 to 9).toArray
xs: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> val k = 6
k: Int = 6
scala> java.util.Arrays.fill(xs, 0, k, xs(k))
scala> xs
res10: Array[Int] = Array(7, 7, 7, 7, 7, 7, 7, 8, 9)
For your second question, if not resizing the collection but editing the elements, stick with array. ArrayBuffer is much like the Java ArrayList, it resizes it self when it needs to, so insertion is amortized constant, not just constant.
For your first question, I'm not aware of any method in the collections library that would allow you to do this. It's obviously syntactic sugar for looping, so if you really care (do you really find yourself needing to do this often?), you can define an implicit class and yourself define a method which loops, and then use that. Write a comment if you would like to see example of such code, otherwise try doing it yourself, it's gonna be good training.
Scala has the Range class. You can convert the Range to an Array if you wish.
scala> val n = 10
n: Int = 10
scala> Range(1,n)
res22: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> res22.toArray
res23: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
│
ArrrayBuffer has constant time update and would be good for updating values.

Scala Set - default behavior

Want to know how scala arranges the data in set.
scala> val imm = Set(1, 2, 3, "four") //immutable variable
imm : scala.collection.immutable.Set[Any] = Set(1, 2, 3, four)
scala> var mu = Set(1, 2, 3, "four", 9)
mu: scala.collection.immutable.Set[Any] = Set(four, 1, 9, 2, 3)
scala> mu += "five"
scala> mu.toString
res1: String = Set(four, 1, 9, 2, 3, five)
Order remains as we insert in case of immutable Set but not in mutable Set.
Also no matter how many times I create a new set with var xyz = Set(1, 2, 3, "four", 9) the order of getting stored remains same Set(four, 1, 9, 2, 3). So it's not storing in random, there is some logic behind it which I want to know. Moreover, is there any advantage of such behavior?
Sets don't have an order. An item is in the set or it isn't. That's all you can know about a set.
If you require a certain ordering, you need to use an ordered set or possibly a sorted set.
Of course, any particular implementation of a set may or may not incidentally have an ordering which may or may not be stable across multiple calls, but that would be a purely accidental implementation detail that may change at any time, during an update of Scala or even between two calls.