I called tail on an Array, but saw a warning.
scala> val arr = Array(1,2)
arr: Array[Int] = Array(1, 2)
scala> arr tail
warning: there were 1 feature warning(s); re-run with -feature for details
res3: Array[Int] = Array(2)
Scaladocs for Array shows an UnsupportedOperationException [will be thrown]
if the mutable indexed sequence is empty.
Is there a safe, won't throw exception, way to get the tail of an array?
Is there a safe, won't throw exception, way to get the tail of an
array?
You can use drop:
scala> Array(1, 2, 3).drop(1)
res0: Array[Int] = Array(2, 3)
scala> Array[Int]().drop(1)
res1: Array[Int] = Array()
Also note that as mentioned by #TravisBrown in the comment below, drop doesn't differentiate between an empty tail (for collections with one element) and the absence of tail (for empty collections) since in both the cases, drop(1) would return an empty collection.
First of all, the warning doesn't have anything to do with the fact that you're using an unsafe method. If you restart the REPL with -feature you'll see the following:
scala> arr tail
<console>:9: warning: postfix operator tail should be enabled
by making the implicit value language.postfixOps visible...
And a pointer to the documentation for scala.language.postfixOps, which includes the following note:
Postfix operators interact poorly with semicolon inference. Most programmers avoid them for this reason.
This is good advice. Being able to write arr tail instead of arr.tail isn't worth the fuss.
Now about the safety issue. The standard library doesn't provide a tailOption for collections, but you can get the same effect using headOption and map:
scala> val arr = Array(1, 2)
arr: Array[Int] = Array(1, 2)
scala> arr.headOption.map(_ => arr.tail)
res0: Option[Array[Int]] = Some([I#359be9fb)
If this is too verbose or opaque or inefficient for you, you can easily create an implicit class that would add a nicer tailOption to Array (or Seq, or IndexedSeq, etc.).
See #TravisBrown's answer for the reason of your warning.
I would personally use a scala.util.Try rather than his rather clever map on the array's head:
scala> val arr = Array(0, 1, 2)
arr: Array[Int] = Array(0, 1, 2)
scala> scala.util.Try {arr.tail} foreach {t => println(t.mkString(","))}
1,2
Related
I have a ListBuffer with thousand elements. After program has done calculations I want to fill it with new data. Is there a way like in C with free() to empty it? Or is it a good way to assign null to my ListBuffer and garbage collector will do all the work?
The method clear does just that.
scala> val xs = scala.collection.mutable.ListBuffer(1,2,3,4,5)
xs: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3, 4, 5)
scala> xs.clear()
scala> xs
res2: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
I am having trouble understanding Scala lists. I just want to create a list of lists: List(list(1,2), List(3,4))
In the REPL I am trying:
val list= List()
val lt = List(1,2)
val ls = List(3,4)
list::lt resolves to - res0: List[Any] = List(List(), 1, 2)
list::ls resolves to - res1: List[Any] = List(List(), 3, 4)
I'm coming from java and have never programmed functionally. I am just not getting it.
Thanks for any help!!
You'll want to read the book, where it explains that cons :: prepends to the thing on the right.
one way to initialize new lists is to string together elements with
the cons operator, with Nil as the last element.
scala> List(1,2) :: Nil
res1: List[List[Int]] = List(List(1, 2))
The book also explains about operators ending in a colon.
If you stick a List[Nothing] on the front of a List[Int], you get the List[Any] you witnessed.
I need to create a new instance of BitSet class from another BitSet object (input).
I expected something like new BitSet(input), but none found. I could get the new instance with map() method as follows, but I don't think this is the best solution.
var r = input.map(_ + 0)(BitSet.canBuildFrom)
What's the copy constructor of BitSet? What's the general rule for copy constructor in Scala?
You can create another with the bitmask of the first:
var r = new BitSet(input.toBitMask)
I think, the general rule is to use immutable collections. They are, well, immutable, so you can pass them around freely without taking special care for copying them.
When you need mutable collections, however, copying collections becomes useful. I discovered that using standard to method works:
scala> mutable.Set(1, 2, 3)
res0: scala.collection.mutable.Set[Int] = Set(1, 2, 3)
scala> res0.to[mutable.Set]
res1: scala.collection.mutable.Set[Int] = Set(1, 2, 3)
scala> res0 eq res1
res2: Boolean = false
However, it won't work with BitSet because it is not a generic collection, and to needs type constructor as its generic parameter. For BitSet you can use the method suggested by Lee. BTW, it is intended exactly for scala.collection.mutable.BitSet, because scala.collection.immutable.BitSet does not contain such constructor (nor does it need it).
The "copy" method on collections is called clone (to be consistent with Java style).
scala> collection.mutable.BitSet(1,2,3)
res0: scala.collection.mutable.BitSet = BitSet(1, 2, 3)
scala> res0.clone
res1: scala.collection.mutable.BitSet = BitSet(1, 2, 3)
scala> res0 += 4
res2: res0.type = BitSet(1, 2, 3, 4)
scala> res1
res40: scala.collection.mutable.BitSet = BitSet(1, 2, 3)
Say I have a method that returns this.
Vector[ (PkgLine, Tree) ]()
I want to convert this to a List of PkgLines. I want to drop the Tree off. I'm not seeing anything in the scala library that would allow me to do this. Anybody have any simple ideas? Thanks.
val list = vector.map(_._1).toList
If you have a Tupel t, you can access its first element using t._1. So with the map operation, you're effectively throwing away the trees, and store the PkgLines directly. Then you simply convert the Vector to List.
Using map with a selector of the first element of the pair works:
scala> val v = Vector[(Int,String)]((5,"5"), (42,"forty-two"))
v: ... = Vector((5,5), (42,forty-two))
scala> v.map(_._1).toList
resN: List[Int] = List(5, 42)
Alternatively, you can use unzip:
scala> val (ints,strings) = v.unzip
ints: scala.collection.immutable.Vector[Int] = Vector(5, 42)
strings: scala.collection.immutable.Vector[String] = Vector(5, forty-two)
scala> ints.toList
resN: List[Int] = List(5, 42)
Concerning the yield command in Scala and the following example:
val values = Set(1, 2, 3)
val results = for {v <- values} yield (v * 2)
Can anyone explain how Scala knows which type of collection to yield into? I know it is based on values, but how would I go about writing code that replicates yield?
Is there any way for me to change the type of the collection to yield into? In the example I want results to be of type List instead of Set.
Failing this, what is the best way to convert from one collection to another? I know about _:*, but as a Set is not a Seq this does not work. The best I could find thus far is val listResults = List() ++ results.
Ps. I know the example does not following the recommended functional way (which would be to use map), but it is just an example.
The for comprehensions are translated by compiler to map/flatMap/filter calls using this scheme.
This excellent answer by Daniel answers your first question.
To change the type of result collection, you can use collection.breakout (also explained in the post I linked above.)
scala> val xs = Set(1, 2, 3)
xs: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
scala> val ys: List[Int] = (for(x <- xs) yield 2 * x)(collection.breakOut)
ys: List[Int] = List(2, 4, 6)
You can convert a Set to a List using one of following ways:
scala> List.empty[Int] ++ xs
res0: List[Int] = List(1, 2, 3)
scala> xs.toList
res1: List[Int] = List(1, 2, 3)
Recommended read: The Architecture of Scala Collections
If you use map/flatmap/filter instead of for comprehensions, you can use scala.collection.breakOut to create a different type of collection:
scala> val result:List[Int] = values.map(2*)(scala.collection.breakOut)
result: List[Int] = List(2, 4, 6)
If you wanted to build your own collection classes (which is the closest thing to "replicating yield" that makes any sense to me), you should have a look at this tutorial.
Try this:
val values = Set(1, 2, 3)
val results = for {v <- values} yield (v * 2).toList