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

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)

Related

Scala Seq's filterNot implementation doesn't accept another List as function input parameter

I'm working with collections and found this a bit weird:
val a = Seq(1, 2, 3, 4, 5, 6)
a.filterNot(Seq(1, 2, 3))
//=> expected output: List(4, 5, 6)
//=> actual: compiler error
<console>:13: error: type mismatch;
found : Int(3)
required: Boolean
a.filterNot(List(1, 2, 3))
But, this version works:
val a = Seq(1, 2, 3, 4, 5, 6)
a.filterNot(Set(1, 2, 3))
//=> expected output: List(4, 5, 6)
//=> actual: List(4, 5, 6)
I wonder why this happens. I read both Seq and Set definitions but found any clue.
An easily overlooked fact is that a Set[A] extends A => Boolean. In other words, a Set is a predicate (one that checks for membership). This is why you can pass a Set to filterNot.
The difference is the apply() method for Seq and Set collections. Look at the definition of filterNot():
def filterNot(p: (A) ⇒ Boolean): Seq[A]
It takes a function that, when fed an element, returns a Boolean. Set does that. Seq does not.
Set(2,3,6).apply(0) //res0: Boolean = false
Seq(2,3,6).apply(0) //res1: Int = 2
So when you invoke a.filterNot(Set(1, 2, 3)), the Set passed in to the filterNot is applied to each of the elements from the Seq, a, which will result in true or false, which is what the filterNot() requires.

Scala: flatMap with tuples

Why is the below statement valid for .map() but not for .flatMap()?
val tupled = input.map(x => (x*2, x*3))
//Compilation error: cannot resolve reference flatMap with such signature
val tupled = input.flatMap(x => (x*2, x*3))
This statement has no problem, though:
val tupled = input.flatMap(x => List(x*2, x*3))
Assuming input if of type List[Int], map takes a function from Int to A, whereas flatMap takes a function from Int to List[A].
Depending on your use case you can choose either one or the other, but they're definitely not interchangeable.
For instance, if you are merely transforming the elements of a List you typically want to use map:
List(1, 2, 3).map(x => x * 2) // List(2, 4, 6)
but you want to change the structure of the List and - for example - "explode" each element into another list then flattening them, flatMap is your friend:
List(1, 2, 3).flatMap(x => List.fill(x)(x)) // List(1, 2, 2, 3, 3, 3)
Using map you would have had List(List(1), List(2, 2), List(3, 3, 3)) instead.
To understand how this is working, it can be useful to explicitly unpack the functions you're sending to map and flatMap and examine their signatures. I've rewritten them here, so you can see that f is a function mapping from Int to an (Int, Int) tuple, and g is a function that maps from Int to a List[Int].
val f: (Int) => (Int, Int) = x => (x*2, x*3)
val g: (Int) => List[Int] = x => List(x*2, x*3)
List(1,2,3).map(f)
//res0: List[(Int, Int)] = List((2,3), (4,6), (6,9))
List(1,2,3).map(g)
//res1: List[List[Int]] = List(List(2, 3), List(4, 6), List(6, 9))
//List(1,2,3).flatMap(f) // This won't compile
List(1,2,3).flatMap(g)
//res2: List[Int] = List(2, 3, 4, 6, 6, 9)
So why won't flatMap(f) compile? Let's look at the signature for flatMap, in this case pulled from the List implementation:
final override def flatMap[B, That](f : scala.Function1[A, scala.collection.GenTraversableOnce[B]])(...)
This is a little difficult to unpack, and I've elided some of it, but the key is the GenTraversableOnce type. List, if you follow it's chain of inheritance up, has this as a trait it is built with, and thus a function that maps from some type A to a List (or any object with the GenTraversableOnce trait) will be a valid function. Notably, tuples do not have this trait.
That is the in-the-weeds explanation why the typing is wrong, and is worth explaining because any error that says 'cannot resolve reference with such a signature' means that it can't find a function that takes the explicit type you're offering. Types are very often inferred in Scala, and so you're well-served to make sure that the type you're giving is the type expected by the method you're calling.
Note that flatMap has a standard meaning in functional programming, which is, roughly speaking, any mapping function that consumes a single element and produces n elements, but your final result is the concatenation of all of those lists. Therefore, the function you pass to flatMap will always expect to produce a list, and no flatMap function would be expected to know how to act on single elements.

How to easily convert IndexedSeq[Array[Int]] to Seq[Seq[Int]] in Scala?

I have a function that takes a list of lists of integer, specifically Seq[Seq[Int]]. Then I produce this data from reading a text file and using split, and that produces a list of Array. That is not recognized by Scala, who raises a match error. But either IndexedSeq or Array alone are OK with a Seq[Int] function, apparently only the nested collection is an issue. How can I convert implicitly IndexedSeq[Array[Int]] to Seq[Seq[Int]], or how else could I do this other than using toList as demonstrated below? Iterable[Iterable[Int]] seems to be fine, for instance, but I can't use this.
scala> def g(x:Seq[Int]) = x.sum
g: (x: Seq[Int])Int
scala> g("1 2 3".split(" ").map(_.toInt))
res6: Int = 6
scala> def f(x:Seq[Seq[Int]]) = x.map(_.sum).sum
f: (x: Seq[Seq[Int]])Int
scala> f(List("1 2 3", "3 4 5").map(_.split(" ").map(_.toInt)))
<console>:9: error: type mismatch;
found : List[Array[Int]]
required: Seq[Seq[Int]]
f(List("1 2 3", "3 4 5").map(_.split(" ").map(_.toInt)))
^
scala> f(List("1 2 3", "3 4 5").map(_.split(" ").map(_.toInt).toList))
res8: Int = 18
The problem is that Array does not implement SeqLike. Normally, implicit conversions to ArrayOps or WrappedArray defined in scala.predef allow to use array just like Seq. However, in your case array is 'hidden' from implicit conversions as a generic argument. One solution would be to hint compiler that you can apply an implicit conversion to the generic argument like this:
def f[C <% Seq[Int]](x:Seq[C]) = x.map(_.sum).sum
This is similar to Paul's response above. The problem is that view bounds are deprecated in Scala 2.11 and using deprecated language features is not a good idea. Luckily, view bounds can be rewritten as context bounds as follows:
def f[C](x:Seq[C])(implicit conv: C => Seq[Int]) = x.map(_.sum).sum
Now, this assumes that there is an implicit conversion from C to Seq[Int], which is indeed present in predef.
How about this:
implicit def _convert(b:List[Array[Int]]):Seq[Seq[Int]]=b.map(_.toList)
Redefine f to be a bit more flexible.
Since Traversable is a parent of List, Seq, Array, etc., f will be compatible with these containers if it based on Traversable. Traversable has sum, flatten, and map, and that is all that's needed.
What is tricky about this is that
def f(y:Traversable[Traversable[Int]]):Int = y.flatten.sum
is finicky and doesn't work on a y of type List[Array[Int]] although it will work on Array[List[Int]]
To make it less finicky, some type view bounds will work.
Initially, I replaced your sum of sums with a flatten/sum operation.
def f[Y<%Traversable[K],K<%Traversable[Int]](y:Y):Int=y.flatten.sum
I found this also seems to work but I did not test as much:
def f[Y <% Traversable[K], K <% Traversable[Int]](y:Y):Int=y.map(_.sum).sum
This <% syntax says Y is viewable as Traversable[K] for some type K that is viewable as a Traversable of Int.
Define some different containers, including the one you need:
scala> val myListOfArray = List(Array(1,2,3),Array(3,4,5))
val myListOfArray = List(Array(1,2,3),Array(3,4,5))
myListOfArray: List[Array[Int]] = List(Array(1, 2, 3), Array(3, 4, 5))
scala> val myArrayOfList = Array(List(1,2,3),List(3,4,5))
val myArrayOfList = Array(List(1,2,3),List(3,4,5))
myArrayOfList: Array[List[Int]] = Array(List(1, 2, 3), List(3, 4, 5))
scala> val myListOfList = List(List(1,2,3),List(3,4,5))
val myListOfList = List(List(1,2,3),List(3,4,5))
myListOfList: List[List[Int]] = List(List(1, 2, 3), List(3, 4, 5))
scala> val myListOfRange = List(1 to 3, 3 to 5)
val myListOfRange = List(1 to 3, 3 to 5)
myListOfRange: List[scala.collection.immutable.Range.Inclusive] = List(Range(1, 2, 3), Range(3, 4, 5))
Test:
scala> f(myListOfArray)
f(myListOfArray)
res24: Int = 18
scala> f(myArrayOfList)
f(myArrayOfList)
res25: Int = 18
scala> f(myListOfList)
f(myListOfList)
res26: Int = 18
scala> f(myListOfRange)
f(myListOfRange)
res28: Int = 18

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)

Scala: Can I rely on the order of items in a Set?

This was quite an unplesant surprise:
scala> Set(1, 2, 3, 4, 5)
res18: scala.collection.immutable.Set[Int] = Set(4, 5, 1, 2, 3)
scala> Set(1, 2, 3, 4, 5).toList
res25: List[Int] = List(5, 1, 2, 3, 4)
The example by itself suggest a "no" answer to my question. Then what about ListSet?
scala> import scala.collection.immutable.ListSet
scala> ListSet(1, 2, 3, 4, 5)
res21: scala.collection.immutable.ListSet[Int] = Set(1, 2, 3, 4, 5)
This one seems to work, but should I rely on this behavior?
What other data structure is suitable for an immutable collection of unique items, where the original order must be preserved?
By the way, I do know about distict method in List. The problem is, I want to enforce uniqueness of items (while preserving the order) at interface level, so using distinct would mess up my neat design..
EDIT
ListSet doesn't seem very reliable either:
scala> ListSet(1, 2, 3, 4, 5).toList
res28: List[Int] = List(5, 4, 3, 2, 1)
EDIT2
In my search for a perfect design I tried this:
scala> class MyList[A](list: List[A]) { val values = list.distinct }
scala> implicit def toMyList[A](l: List[A]) = new MyList(l)
scala> implicit def fromMyList[A](l: MyList[A]) = l.values
Which actually works:
scala> val l1: MyList[Int] = List(1, 2, 3)
scala> l1.values
res0: List[Int] = List(1, 2, 3)
scala> val l2: List[Int] = new MyList(List(1, 2, 3))
l2: List[Int] = List(1, 2, 3)
The problem, however, is that I do not want to expose MyList outside the library. Is there any way to have the implicit conversion when overriding? For example:
trait T { def l: MyList[_] }
object O extends T { val l: MyList[_] = List(1, 2, 3) }
scala> O.l mkString(" ") // Let's test the implicit conversion
res7: String = 1 2 3
I'd like to do it like this:
object O extends T { val l = List(1, 2, 3) } // Doesn't work
That depends on the Set you are using. If you do not know which Set implementation you have, then the answer is simply, no you cannot be sure. In practice I usually encounter the following three cases:
I need the items in the Set to be ordered. For this I use classes mixing in the SortedSet trait which when you use only the Standard Scala API is always a TreeSet. It guarantees the elements are ordered according to their compareTo method (see the Ordered trat). You get a (very) small performance penalty for the sorting as the runtime of inserts/retrievals is now logarithmic, not (almost) constant like with the HashSet (assuming a good hash function).
You need to preserve the order in which the items are inserted. Then you use the LinkedHashSet. Practically as fast as the normal HashSet, needs a little more storage space for the additional links between elements.
You do not care about order in the Set. So you use a HashSet. (That is the default when using the Set.apply method like in your first example)
All this applies to Java as well, Java has a TreeSet, LinkedHashSet and HashSet and the corresponding interfaces SortedSet, Comparable and plain Set.
It is my belief that you should never rely on the order in a set. In no language.
Apart from that, have a look at this question which talks about this in depth.
ListSet will always return elements in the reverse order of insertion because it is backed by a List, and the optimal way of adding elements to a List is by prepending them.
Immutable data structures are problematic if you want first in, first out (a queue). You can get O(logn) or amortized O(1). Given the apparent need to build the set and then produce an iterator out of it (ie, you'll first put all elements, then you'll remove all elements), I don't see any way to amortize it.
You can rely that a ListSet will always return elements in last in, first out order (a stack). If that suffices, then go for it.