What is the difference between val b=a (a is an Array) and val b=a.clone()? - scala

I am reading scaladocs and just wondering difference between direct assignment and .clone method.
val a=Array(1,2,3,4,5)
case 1:
val b=a
case 2 :
val b=a.clone()

Consider this:
scala> val a=Array(1,2,3,4,5)
a: Array[Int] = Array(1, 2, 3, 4, 5)
scala> val b = a
b: Array[Int] = Array(1, 2, 3, 4, 5)
scala> val c = a.clone()
c: Array[Int] = Array(1, 2, 3, 4, 5)
scala> b(0) = 0
scala> c(1) = 1
scala> a
res2: Array[Int] = Array(0, 2, 3, 4, 5)
scala> b
res3: Array[Int] = Array(0, 2, 3, 4, 5)
scala> c
res4: Array[Int] = Array(1, 1, 3, 4, 5)
As you can see, when you do val b = a, then a and b point to the same object. When the object is changed, the change will be seen by both.
On the other hand, when you clone the array, you produce a new array with the same content. Changing this new array does not change the old one.

I believe case 1 just sets the reference of a to b while case 2 creates an entirely new array that is a copy of a and putting the value in b.
In other words if you in case a edit the a array the b array will also be edited this is not the case in case 2

Here is an answer in code:
scala> val a = Array(1,2,3,4,5)
scala> a.hashCode()
res12: Int = 1382155266
scala> val b = a
scala> b.hashCode()
res13: Int = 1382155266
scala> val c = a.clone()
scala> c.hashCode()
res14: Int = 2062756135
scala> a eq b
res15: Boolean = true
scala> a eq c
res16: Boolean = false
scala> b eq c
res17: Boolean = false

In case 1, both reference leads to the same object while in the second case, a new object is created and a and b do not reference the same object.

Related

Ommiting parenthesis in adding elements to List

I'm trying to add element to a List[String] while omitting annoying parenthesis. I tried this:
object Main extends App {
val l = List("fds")
val xs1: List[String] = l.+:("123") // ok
val xs2: List[String] = l +: "123" // compile-error
}
DEMO
Why is omitting parenthesis causing compile-error? These assignments look the same to me. What is the difference?
It's happening because of right associative methods.
scala> val l = List("abc")
l: List[String] = List(abc)
scala> "efg" +: l
res3: List[String] = List(efg, abc)
Read more here What good are right-associative methods in Scala?
Error case
scala> val l = List(1, 2, 3)
l: List[Int] = List(1, 2, 3)
scala> 4 +: l
res1: List[Int] = List(4, 1, 2, 3)
scala> l +: 1
<console>:13: error: value +: is not a member of Int
l +: 1
^
Because +: is right associative. Method +: is getting invoked on Int instead of list
In order to make it work we can explicitly invoke method on list without the special operator syntax
scala> val l = List(1, 2, 3)
l: List[Int] = List(1, 2, 3)
scala> l.+:(1)
res4: List[Int] = List(1, 1, 2, 3)
Above case works because its normal method invocation.

How can I define a ScalaCheck generator that produces a subset of a sequence's elements?

How can I pick a subset of the elements of a sequence?
For instance, if I had the sequence Seq(1,2,3,4,5), I'd like each call to my generator to produce something like
Seq(1,4)
or
Seq(1,2,3,5)
or
Seq()
How can I define such a generator?
org.scalacheck.Gen.someOf is a generator that picks a random number of elements from an iterable:
scala> import org.scalacheck.Gen
import org.scalacheck.Gen
scala> val baseSeq = Seq(1, 2, 3, 4, 5)
baseSeq: Seq[Int] = List(1, 2, 3, 4, 5)
scala> val myGen = Gen.someOf(baseSeq).map(_.toSeq)
myGen: org.scalacheck.Gen[Seq[Int]] = org.scalacheck.Gen$$anon$6#ff6a218
scala> myGen.sample.head
res0: Seq[Int] = List(3, 4, 5)
scala> myGen.sample.head
res1: Seq[Int] = List(1, 2, 3, 4)
scala> myGen.sample.head
res2: Seq[Int] = List()
This depends on the probability for each element to show up in your result. For example, for any element to show up with 50% chance, you can use the following. Hope this helps.
import scala.util.Random
val s = Seq(1,2,3,4,5)
s filter { i => Random.nextInt(2) == 1 }

Is there a Round Robin/Circular Queue available in Scala Collections

Is there a Round Robin Queue available in Scala Collections?
I need to repeatedly iterate a list that circles through itself
val x = new CircularList(1,2,3,4)
x.next (returns 1)
x.next (returns 2)
x.next (returns 3)
x.next (returns 4)
x.next (returns 1)
x.next (returns 2)
x.next (returns 3)
... and so on
It's pretty easy to roll your own with continually and flatten:
scala> val circular = Iterator.continually(List(1, 2, 3, 4)).flatten
circular: Iterator[Int] = non-empty iterator
scala> circular.take(17).mkString(" ")
res0: String = 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
There's also a continually method on Stream—just be careful not to hold onto a reference to the head of the stream if you're going to be generating lots of elements.
You can very easily create a circular list using a Stream.
scala> val l = List(1, 2, 3, 4).toStream
l: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> def b: Stream[Int] = l #::: b
b: Stream[Int]
scala> b.take(20).toList
res2: List[Int] = List(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4)
Edit: you want to make sure to define the repeated part beforehand, once and only once, to avoid blowing the heap (structural sharing in Stream). As in:
def circular[A](a: Seq[A]): Stream[A] = {
val repeat = a.toStream
def b: Stream[A] = repeat #::: b
b
}
Version more concentrated on getting new element on every execution.
val getNext: () => Int = {
def b: Stream[Int] = List(1, 2, 3, 4).toStream #::: b
var cyclicIterator: Stream[Int] = b
() => {
val tail = cyclicIterator.tail
val result = tail.head
cyclicIterator = tail
result
}
} // could be written more sexy?
In your problem you can use it like:
for(i <- 1 to 10) yield getNext()
This is ugly in having an external mutable index, but it does do what's requested:
scala> var i = 0
scala> val ic4 = Iterator.continually { val next = IndexedSeq(1, 2, 3, 4)(i % 4); i += 1; next }
i: Int = 0
ic4: Iterator[Int] = non-empty iterator
scala> ic4 take 10 foreach { i => printf("ic4.next=%d%n", i) }
ic4.next=1
ic4.next=2
ic4.next=3
ic4.next=4
ic4.next=1
ic4.next=2
ic4.next=3
ic4.next=4
ic4.next=1
ic4.next=2
At least it illustrates Iterator.continually. There is also Stream.continually, which has the same signature.

How can I sort List[Int] objects?

What I want to do is sort List objects in Scala, not sort the elements in the list. For example If I have two lists of Ints:
val l1 = List(1, 2, 3, 7)
val l2 = List(1, 2, 3, 4, 10)
I want to be able to put them in order where l1 > l2.
I have created a case class that does what I need it to but the problem is that when I use it none of my other methods work. Do I need to implement all the other methods in the class i.e. flatten, sortWith etc.?
My class code looks like this:
class ItemSet(itemSet: List[Int]) extends Ordered[ItemSet] {
val iSet: List[Int] = itemSet
def compare(that: ItemSet) = {
val thisSize = this.iSet.size
val thatSize = that.iSet.size
val hint = List(thisSize, thatSize).min
var result = 0
var loop = 0
val ths = this.iSet.toArray
val tht = that.iSet.toArray
while (loop < hint && result == 0) {
result = ths(loop).compare(tht(loop))
loop += 1
}
if (loop == hint && result == 0 && thisSize != thatSize) {
thisSize.compare(thatSize)
} else
result
}
}
Now if I create an Array of ItemSets I can sort it:
val is1 = new ItemSet(List(1, 2, 5, 8))
val is2 = new ItemSet(List(1, 2, 5, 6))
val is3 = new ItemSet(List(1, 2, 3, 7, 10))
Array(is1, is2, is3).sorted.foreach(i => println(i.iSet))
scala> List(1, 2, 3, 7, 10)
List(1, 2, 5, 6)
List(1, 2, 5, 8)
The two methods that are giving me problems are:
def itemFrequencies(transDB: Array[ItemSet]): Map[Int, Int] = transDB.flatten.groupBy(x => x).mapValues(_.size)
The error I get is:
Expression of type Map[Nothing, Int] doesn't conform to expected type Map[Int, Int]
And for this one:
def sortListAscFreq(transDB: Array[ItemSet], itemFreq: Map[Int, Int]): Array[List[Int]] = {
for (l <- transDB) yield
l.sortWith(itemFreq(_) < itemFreq(_))
}
I get:
Cannot resolve symbol sortWith.
Is there a way I can just extend List[Int] so that I can sort a collection of lists without loosing the functionality of other methods?
The standard library provides a lexicographic ordering for collections of ordered things. You can put it into scope and you're done:
scala> import scala.math.Ordering.Implicits._
import scala.math.Ordering.Implicits._
scala> val is1 = List(1, 2, 5, 8)
is1: List[Int] = List(1, 2, 5, 8)
scala> val is2 = List(1, 2, 5, 6)
is2: List[Int] = List(1, 2, 5, 6)
scala> val is3 = List(1, 2, 3, 7, 10)
is3: List[Int] = List(1, 2, 3, 7, 10)
scala> Array(is1, is2, is3).sorted foreach println
List(1, 2, 3, 7, 10)
List(1, 2, 5, 6)
List(1, 2, 5, 8)
The Ordering type class is often more convenient than Ordered in Scala—it allows you to specify how some existing type should be ordered without having to change its code or create a proxy class that extends Ordered[Whatever], which as you've seen can get messy very quickly.

Replace element in List with scala

How do you replace an element by index with an immutable List.
E.g.
val list = 1 :: 2 ::3 :: 4 :: List()
list.replace(2, 5)
If you want to replace index 2, then
list.updated(2,5) // Gives 1 :: 2 :: 5 :: 4 :: Nil
If you want to find every place where there's a 2 and put a 5 in instead,
list.map { case 2 => 5; case x => x } // 1 :: 5 :: 3 :: 4 :: Nil
In both cases, you're not really "replacing", you're returning a new list that has a different element(s) at that (those) position(s).
In addition to what has been said before, you can use patch function that replaces sub-sequences of a sequence:
scala> val list = List(1, 2, 3, 4)
list: List[Int] = List(1, 2, 3, 4)
scala> list.patch(2, Seq(5), 1) // replaces one element of the initial sequence
res0: List[Int] = List(1, 2, 5, 4)
scala> list.patch(2, Seq(5), 2) // replaces two elements of the initial sequence
res1: List[Int] = List(1, 2, 5)
scala> list.patch(2, Seq(5), 0) // adds a new element
res2: List[Int] = List(1, 2, 5, 3, 4)
You can use list.updated(2,5) (which is a method on Seq).
It's probably better to use a scala.collection.immutable.Vector for this purpose, becuase updates on Vector take (I think) constant time.
You can use map to generate a new list , like this :
# list
res20: List[Int] = List(1, 2, 3, 4, 4, 5, 4)
# list.map(e => if(e==4) 0 else e)
res21: List[Int] = List(1, 2, 3, 0, 0, 5, 0)
It can also be achieved using patch function as
scala> var l = List(11,20,24,31,35)
l: List[Int] = List(11, 20, 24, 31, 35)
scala> l.patch(2,List(27),1)
res35: List[Int] = List(11, 20, 27, 31, 35)
where 2 is the position where we are looking to add the value, List(27) is the value we are adding to the list and 1 is the number of elements to be replaced from the original list.
If you do a lot of such replacements, it is better to use a muttable class or Array.
following is a simple example of String replacement in scala List, you can do similar for other types of data
scala> val original: List[String] = List("a","b")
original: List[String] = List(a, b)
scala> val replace = original.map(x => if(x.equals("a")) "c" else x)
replace: List[String] = List(c, b)