How to enforce a Collection (Seq, List etc.) to accept only positive integers - Scala - scala

I would ideally like to enforce a Collection in Scala to allow only positive integers. Is there way?
I can achieve it at run time by wrapping a Sequence in a class and verifying it's initialization, but that would mean handling exception at run time. A compile time solution would be nicer.

You can use refined to define a List[Int ## Positive], that is a list of Ints that are greater than zero. refined will then check at compile-time that all elements in your list are positive:
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric.Positive
import shapeless.tag.##
scala> val posInts: List[Int ## Positive] = List(1, 2, 3)
posInts: List[Int ## Positive] = List(1, 2, 3)
If you try to put a non-positive Int in the List, you'll get a compile error:
scala> val posInts: List[Int ## Positive] = List(1, 2, 3, -4)
<console>:43: error: Predicate failed: (-4 > 0).
val posInts: List[Int ## Positive] = List(1, 2, 3, -4)
^

Related

How to pass ordering to scala.util.Sorting.quickSort

I'm trying to pass reverse ordering to the scala.util.Sorting.quickSort with this code:
val a = Array(3, 5, 1, 2)
scala.util.Sorting.quickSort(a)(Ordering.Int.reverse)
It doesn't work saying that:
Error: Unit does not take parameters
However, the code like that works:
val a = Array(3, 5, 1, 2)
a.sorted(Ordering.Int.reverse)
I don't understand why the quickSort example doesn't work? The Ordering.Int.reverse produce Ordering[Int] and according to documentation, the quickSort accepts it implicitly.
I'm running with Scala 2.12.7.
Expanding on Yuval Itzchakov's comment, here is the source code for scala.util.Sorting.quickSort:
def quickSort(a: Array[Int]): Unit = java.util.Arrays.sort(a)
A few lines down, another overloaded quicksort is defined as:
def quickSort[K: Ordering](a: Array[K]): Unit = {...
You mean to use this latter one. But when you call quickSort, the compiler is picking the first one which does not accept an Ordering in its parameter list so it complains about extra parameters. You will need to specify type parameter if you are using Int, Double, or Float as explained here. To summarize:
val a : Array[Int] = Array(3, 5, 1, 2)
val b = Array(3L, 5L, 1L, 2L) //Longs do not have this problem!
scala.util.Sorting.quickSort[Int](a)(Ordering.Int.reverse)
scala.util.Sorting.quickSort(b)(Ordering.Long.reverse)
println(a.toList)
println(b.toList)
List(5, 3, 2, 1)
List(5, 3, 2, 1)
According to documentation the signature of method that uses Ordering is:
def quickSort[K](a: Array[K])(implicit arg0: math.Ordering[K]): Unit
Sort array a with quicksort, using the Ordering on its elements. This
algorithm sorts in place, so no additional memory is used aside from
what might be required to box individual elements during comparison.
try this:
scala> val a = Array(3, 5, 1, 2)
a: Array[Int] = Array(3, 5, 1, 2)
scala> scala.util.Sorting.quickSort(a)(Ordering.Int.reverse)
<console>:13: error: Unit does not take parameters
scala.util.Sorting.quickSort(a)(Ordering.Int.reverse)
^
scala> scala.util.Sorting.quickSort[Int](a)(Ordering[Int].reverse)
scala> a
res2: Array[Int] = Array(5, 3, 2, 1)

Cannot construct a collection of type ...Inclusive[Long] with elements of type Long based on a collection of type ...Inclusive[Long]

I'm not sure I understand why the following happens.
Compiles and works:
With Ints without converting to a List
import scala.util.Random
val xs = 1 to 10
Random.shuffle(xs)
With Longs after converting to a List
import scala.util.Random
val xs = 1L to 10L
Random.shuffle(xs.toList) //<-- I had to materialize it to a list
Doesn't compile
With Longs without converting to a List
val xs = 1L to 10L
Random.shuffle(xs)
This one throws this exception:
Error: Cannot construct a collection of type
scala.collection.immutable.NumericRange.Inclusive[Long] with elements of type
Long based on a collection of type
scala.collection.immutable.NumericRange.Inclusive[Long].
Random.shuffle(xs)
^
I'm curious why? Is that because there is a missing CanBuildFrom or something like that? Is there a good reason why there isn't one?
(scala version 2.11.5)
That's because of both CanBuildFrom(1) and type inference mechanism(2).
1) You may find that genericBuilder of Range/NumericRange (same for Inclusive) is:
genericBuilder[B]: Builder[B, IndexedSeq[B]]
So there is only CanBuildFrom[Range, B, IndexedSeq], which uses this builder. The reason why is simple, you may find it in builder's description:
A builder lets one construct a collection incrementally, by adding elements to the builder with += and then converting to the required collection type with result.
You just can't construct inclusive range incrementally, as it won't be a range anymore then (but still be an IndexedSeq); however, you can do such constructions with Seq.
Just to demonstrate the difference between IndexedSeq and Inclusive
scala> (1 to 5)
res14: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5)
scala> (1 to 5) ++ (7 to 10) //builder used here
res15: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 7, 8, 9, 10)
This means that you can't "build" any range, regardless Int (Range) or Long (Numeric) and you should always pass IndexedSeq as To parameter of the builder. However, IndexedSeq is automatically specified for Int (Range), when you pass it to the shuffle function.
2) It's not working for NumericRange.Inclusive[T] because it's a polymorphic type (generic). While, regular Range.Inclusive (not generic) explicitly extends IndexedSeq[Int]. Looking on shuffle signature:
shuffle[T, CC[X] <: TraversableOnce[X]](xs: CC[T])(implicit bf: CanBuildFrom[CC[T], T, CC[T]]): CC[T]
Higher-order type CC is becoming NumericRange.Inclusive here as it's the biggest parametrized type inherited by NumericRange.Inclusive. In case of Range.Inclusive, that was an IndexedSeq (as smaller Range.Inclusive is not generic). So Range.Inclusive just got lucky to be not affected by (1).
Finally, this will work:
scala> Random.shuffle[Long, IndexedSeq](xs)
res8: IndexedSeq[Long] = Vector(9, 3, 8, 6, 7, 2, 5, 4, 10, 1)
scala> Random.shuffle(xs: IndexedSeq[Long])
res11: IndexedSeq[Long] = Vector(6, 9, 7, 3, 1, 8, 5, 10, 4, 2)

Convert Seq to ArrayBuffer

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).

Repeating a List in Scala

I am a Scala noob. I have decided to write a spider solitaire solver as a first exercise to learn the language and functional programming in general.
I would like to generate a randomly shuffled deck of cards containing 1, 2, or 4 suits. Here is what I came up with:
val numberOfSuits = 1
(List("clubs", "diamonds", "hearts", "spades").take(numberOfSuits) * 4).take(4)
which should return
List("clubs", "clubs", "clubs", "clubs")
List("clubs", "diamonds", "clubs", "diamonds")
List("clubs", "diamonds", "hearts", "spades")
depending on the value of numberOfSuits, except there is no List "multiply" operation that I can find. Did I miss it? Is there a better way to generate the complete deck before shuffling?
BTW, I plan on using an Enumeration for the suits, but it was easier to type my question with strings. I will take the List generated above and using a for comprehension, iterate over the suits and a similar List of card "ranks" to generate a complete deck.
Flatten a finite lists of lists:
scala> List.fill(2)(List(1, 2, 3, 4)).flatten
res18: List[Int] = List(1, 2, 3, 4, 1, 2, 3, 4)
Flatten an infinite Stream of lists, take the first N elements:
scala> Stream.continually(List(1, 2, 3, 4)).flatten.take(8).toList
res19: List[Int] = List(1, 2, 3, 4, 1, 2, 3, 4)
You should look up the scaladoc for the object List. It has all manners of interesting methods for creation of lists. For instance, the following does exactly what you were trying to:
List.flatten(List.make(4, List("clubs", "diamonds", "hearts", "spades").take(numberOfSuits))).take(4)
A much nicer code, however, would be this (Scala 2.7):
val suits = List("clubs", "diamonds", "hearts", "spades")
List.tabulate(4, i => suits.apply(i % numberOfSuits))
On Scala 2.8 tabulate is curried, so the correct syntax would be:
List.tabulate(4)(i => suits.apply(i % numberOfSuits))
You can expand a numeric sequence and flatMap instead of multiplying.
scala> (1 to 3).flatMap(_=>List(1,2,3,4).take(2)).take(4)
res1: Seq[Int] = List(1, 2, 1, 2)
This works in 2.7.x also.
Edit: since you're less experienced with Scala, you may not yet have come across the enrich-my-library pattern. If you want to multiply your lists a lot, you can add a custom conversion class:
class MultipliableList[T](l: List[T]) {
def *(n: Int) = (1 to n).flatMap(_=>l).toList
}
implicit def list2multipliable[T](l: List[T]) = new MultipliableList[T](l)
and now you can
scala> List(1,2,3)*4
res2: List[Int] = List(1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3)
(Generally, to reuse such implicits, declare them in an object and then import MyObject._ to get the implicit conversion and corresponding class in scope.)
If you use cats library, you can make use of Semigroup's method combineN. It repeates a list N times.
import cats.implicits._
import cats.syntax.semigroup._
scala> List("clubs", "diamonds", "hearts", "spades").combineN(2)
res1: List[String] = List(clubs, diamonds, hearts, spades, clubs, diamonds, hearts, spades)

Are there any methods included in Scala to convert tuples to lists?

I have a Tuple2 of List[List[String]] and I'd like to be able to convert the tuple to a list so that I can then use List.transpose(). Is there any way to do this? Also, I know it's a Pair, though I'm always a fan of generic solutions.
Works with any tuple (scala 2.8):
myTuple.productIterator.toList
Scala 2.7:
(0 to (myTuple.productArity-1)).map(myTuple.productElement(_)).toList
Not sure how to maintain type info for a general Product or Tuple, but for Tuple2:
def tuple2ToList[T](t: (T,T)): List[T] = List(t._1, t._2)
You could, of course, define similar type-safe conversions for all the Tuples (up to 22).
Using Shapeless -
# import syntax.std.tuple._
import syntax.std.tuple._
# (1,2,3).toList
res21: List[Int] = List(1, 2, 3)
# (1,2,3,4,3,3,3,3,3,3,3).toList
res22: List[Int] = List(1, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3)
Note that type information is not lost using Shapeless's toList.