Convert Seq to ArrayBuffer - scala

Is there any concise way to convert a Seq into ArrayBuffer in Scala?

scala> val seq = 1::2::3::Nil
seq: List[Int] = List(1, 2, 3)
scala> seq.toBuffer
res2: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3)
EDIT After Scala 2.1x, there is a method .to[Coll] defined in TraversableLike, which can be used as follow:
scala> import collection.mutable
import collection.mutable
scala> seq.to[mutable.ArrayBuffer]
res1: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)
scala> seq.to[mutable.Set]
res2: scala.collection.mutable.Set[Int] = Set(1, 2, 3)

This will work:
ArrayBuffer(mySeq : _*)
Some explanations: this uses the apply method in the ArrayBuffer companion object. The signature of that method is
def apply [A] (elems: A*): ArrayBuffer[A]
meaning that it takes a variable number of arguments. For instance:
ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8)
is also a valid call. The ascription : _* indicates to the compiler that a Seq should be used in place of that variable number of arguments (see Section 4.6.2 in the Scala Reference).

Related

List type mismatch when appending in Scala

Let's say I have following code:
val xs: List[Int] = List(1, 2, 3)
val ys: List[Int] = List(4, 5, 6)
val zs: List[Int] = xs.appended(ys)
The last line does not compile with an error:
Error:(162, 33) type mismatch; found : List[Int] required: Int val
zs: List[Int] = xs.appended(ys)
If I remove the explicit type declaration, then the code compiles, but the real problem is that
the error message appears in a recursive function where I would like to pass appended list as a parameter of type List[Int], so removing the explicit type is not an option.
According to scaladoc appended method takes only one argument, not an entire list. So the following examples will compile:
xs.appended(ys(0))
for(x <- xs) yield ys appended x
or appendAll:
xs appendAll ys
ys :++ xs
P.S.: Note, that appending to the list is not optimal, as it's time is proportional to the size of the list, prefer prepend instead:
ys ::: xs
According scala documentation appended method accepting just one element, not collection. And zs type after removing explicit types will be List[Any]:
val xs = List(1, 2, 3)
val ys = List(4, 5, 6)
val zs: List[Any] = xs.appended(ys) // List(1, 2, 3, List(4, 5, 6))
it compiles, but result will be List(1, 2, 3, List(4, 5, 6))
You can use method appendedAll to do that you want or just concatenate lists using concat or ++ operator :
val xs = List(1, 2, 3)
val ys = List(4, 5, 6)
val zs: List[Int] = xs ++ ys // List(1, 2, 3, 4, 5, 6)
val as: List[Int] = xs.appendedAll(ys) // List(1, 2, 3, 4, 5, 6)
val bs: List[Int] = xs.concat(ys) // List(1, 2, 3, 4, 5, 6)
1. val xs: List[Int] = List(1, 2, 3)
2. val ys: List[Int] = List(4, 5, 6)
3. val zs: List[Int] = xs.appended(ys)
The third line is a problem until you have the type declaration. Because when you compile your code compiler is not going to infer the type of the variable zs and it will expect the output of xs.appended(ys) to be a List[Int] which is not the case because xs is List[Int] now if you want to add an element in this list you can do xs.append(1) or any other integer but you are trying to insert List[Int] which is not Int.
Now when you remove the type declaration from line 3 it compile successfully because now compiler will infer the type of the variable zs and if you will see on REPL it will say the of this variable zs is List[Any].
Now if you want to add list into a list and get a flatten result you can simply use
val zs: List[Int] = xs ::: ys
If you will see the scala docs here
this is the signature of appended:
final def:+[B >: A](elem: B): List[B]
:+ is Alias for appended
:++ is Alias for appendedAll
As we can see from the signature appended function takes a parameter of type B and return List[B] in your case B is Int and you are trying to add List[Int].
I hope it clears why you are getting the compilation error.

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 }

Why does List.toString and Vector.toString return a nice representation but not Array.toString?

scala> Array(1, 2, 3).toString
res1: String = [I#11cf437c
scala> List(1, 2, 3).toString
res2: String = List(1, 2, 3)
scala> Vector(1, 2, 3).toString
res3: String = Vector(1, 2, 3)
Logically, one would expect Array(1, 2, 3).toString to return "Array(1, 2, 3)".
Update: seems to me like Array maps to the built in Java array type—is this correct? and if yes, is this the reason Array.toString has to behave like this?
It is because Array is a Java object. You can however use runtime.ScalaRunTime.stringOf if it suits your needs.
scala> runtime.ScalaRunTime.stringOf(Array(1, 2, 3))
res3: String = Array(1, 2, 3)
scala> List(1,2,3).getClass()
res0: Class[_ <: List[Int]] = class scala.collection.immutable.$colon$colon
scala> Vector(1,2,3).getClass()
res1: Class[_ <: scala.collection.immutable.Vector[Int]] = class scala.collection.immutable.Vector
scala> Array(1,2,3).getClass()
res2: Class[_ <: Array[Int]] = class [I
List and Vector are Scala classes, so they have a nice representation. Array comes from Java and practices Java's ugliness.

Scala convert Iterable or collection.Seq to collection.immutable.Seq

It appears the toSeq method in Scala collections returns a scala.collection.Seq, I could also return a Traversable or Iterable but need to convert this to a scala.collection.immutable.Seq.
Is there an easy way to do this?
Thanks
Richard
Use the to method to convert between arbitrary collection types in Scala 2.10:
scala> Array(1, 2, 3).toSeq
res0: Seq[Int] = WrappedArray(1, 2, 3)
scala> Array(1, 2, 3).to[collection.immutable.Seq]
res1: scala.collection.immutable.Seq[Int] = Vector(1, 2, 3)

Convert an array to a mutable set in Scala?

How does one convert a Scala Array to a mutable.Set?
It's easy to convert to an immutable.Set:
Array(1, 2, 3).toSet
But I can't find an obvious way to convert to a mutable.Set.
scala> val s=scala.collection.mutable.Set()++Array(1,2,3)
s: scala.collection.mutable.Set[Int] = Set(2, 1, 3)
scala> scala.collection.mutable.Set( Array(1,2) :_* )
res2: scala.collection.mutable.Set[Int] = Set(2, 1)
The weird :_* type ascription, forces factory method to see the array as a list of arguments.
Starting Scala 2.10, via factory builders applied with .to(factory):
Array(1, 2, 3).to[collection.mutable.Set]
// collection.mutable.Set[Int] = Set(1, 2, 3)
And starting Scala 2.13:
Array(1, 2, 3).to(collection.mutable.Set)
// collection.mutable.Set[Int] = HashSet(1, 2, 3)