What is a good implementation of generic 2D Array literals in scala3 based on tuples? - scala

The following code is a proof-of-concept for an uncluttered way to declare 2D array literals in scala3. It's based on this answer to a related question, implemented for scala2:
https://stackoverflow.com/a/13863525/666886
The non-generic code below provides a clean Array literal declaration, but is inflexible w.r.t. type and dimension. It would be better to derive array dimensions from tuple arity and number of rows.
#!/usr/bin/env scala3
object Array2d {
def main(args: Array[String]): Unit = {
prettyPrintArray()
}
type X=Int
type Tuple26 = (X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X)
type Array2d = Array[Array[X]]
def apply(tuples: Tuple26 *): Array2d = {
for {
tupe <- tuples
row = for ( i <- tupe.toList ) yield i
} yield row.toArray
}.toArray
lazy val letterFrequencies = Array2d(
(46,615,763,839,1745,325,628,651,1011,128,573,1319,797,1123,884,726,49,1642,2241,1162,631,299,408,97,659,184),
(15,103,128,202,597,49,126,107,358,32,123,321,171,226,483,38,6,439,565,233,340,21,58,21,227,40),
(63,128,106,218,689,86,75,407,526,14,241,369,197,307,627,208,5,507,675,343,361,60,66,24,226,28),
(39,202,218,149,1257,108,183,175,634,35,140,407,212,418,692,194,10,596,763,272,409,97,184,52,348,46),
(745,597,689,1257,919,396,568,583,1214,111,504,1315,726,1083,1217,763,34,1876,2323,1223,662,437,455,199,655,187),
(25,49,86,108,396,118,75,72,295,11,68,258,58,129,248,26,7,299,415,208,205,14,50,20,151,24),
(28,126,75,183,568,75,99,141,424,24,55,324,146,416,476,129,3,423,536,206,326,48,66,4,244,28),
(51,107,407,175,583,72,141,53,399,21,145,282,198,238,488,174,6,342,715,454,285,44,158,14,207,23),
(11,358,526,634,1214,295,424,399,169,71,392,853,518,884,594,467,50,970,1471,853,335,246,215,104,323,130),
(28,32,14,35,111,11,24,21,71,2,31,41,28,52,98,26,1,45,112,33,75,9,12,1,38,3),
(73,123,241,140,504,68,55,145,392,31,61,247,102,300,376,152,8,338,744,184,240,21,86,2,224,20),
(319,321,369,407,1315,258,324,282,853,41,247,250,341,369,875,395,10,468,1237,491,566,173,201,61,463,50),
(97,171,197,212,726,58,146,198,518,28,102,341,102,257,555,195,6,429,769,273,401,33,61,40,260,44),
(123,226,307,418,1083,129,416,238,884,52,300,369,257,159,849,265,18,533,1027,537,499,113,220,45,374,65),
(84,483,627,692,1217,248,476,488,594,98,376,875,555,849,525,566,18,1096,1658,856,462,175,329,85,521,130),
(26,38,208,194,763,26,129,174,467,26,152,395,195,265,566,127,8,488,874,347,353,35,83,24,333,28),
(9,6,5,10,34,7,3,6,50,1,8,10,6,18,18,8,1,16,37,25,96,0,2,0,7,1),
(642,439,507,596,1876,299,423,342,970,45,338,468,429,533,1096,488,16,246,1461,789,673,189,234,52,491,77),
(241,565,675,763,2323,415,536,715,1471,112,744,1237,769,1027,1658,874,37,1461,717,1367,1088,221,484,86,598,105),
(162,233,343,272,1223,208,206,454,853,33,184,491,273,537,856,347,25,789,1367,254,548,72,202,49,384,52),
(31,340,361,409,662,205,326,285,335,75,240,566,401,499,462,353,96,673,1088,548,73,61,41,32,317,51),
(99,21,60,97,437,14,48,44,246,9,21,173,33,113,175,35,0,189,221,72,61,20,25,10,63,7),
(8,58,66,184,455,50,66,158,215,12,86,201,61,220,329,83,2,234,484,202,41,25,11,12,133,19),
(7,21,24,52,199,20,4,14,104,1,2,61,40,45,85,24,0,52,86,49,32,10,12,1,34,2),
(59,227,226,348,655,151,244,207,323,38,224,463,260,374,521,333,7,491,598,384,317,63,133,34,43,54),
(84,40,28,46,187,24,28,23,130,3,20,50,44,65,130,28,1,77,105,52,51,7,19,2,54,42),
)
def prettyPrintArray(): Unit = {
val alphabet = "abcdefghijklmnopqrstuvwxyz"
val toprow = alphabet.map { "%4s".format(_) }.mkString(",")
printf("// %s\n", toprow)
for (a <- alphabet){
val freqs: Seq[String] = for {
b <- alphabet
(x,y) = (alphabet.indexOf(a), alphabet.indexOf(b))
freq = letterFrequencies(x)(y)
} yield "%4d".format(freq)
printf("/* %s */ (%s),\n", a, freqs.mkString(","))
}
}
}

The following works, but the same thing based on the new scala 3 type IArray would be nice to have as well.
#!/usr/bin/env scala3
// Example of declaring a generic NxN Array[Array[_]] in scala3 by using
// scala 3 tuple extensions, for a concise declaration of a 2d array.
// An improved version would avoid the deprecated ClassTag reference,
// and the use of `asInstanceOf[List[T]]`.
// Perhaps `shapeless 3` would help in this regard?
object Array2d {
def main(args: Array[String]): Unit = {
prettyPrintArray()
}
// it would be nice if a Tuple with a single homogeneous field Type
// automatically converted to an Array of that type, rather
// than an Array[AnyRef]
import scala.reflect.ClassTag
def apply[T:ClassTag](tuples: Tuple *): Array[Array[T]] = {
val rows: Seq[Array[T]] = for {
tupe <- tuples
row: Seq[T] = tupe.toList.asInstanceOf[List[T]]
arr: Array[T] = (for (i:T <- row) yield i).toArray
} yield arr
rows.toArray
}
// this table is useful for analyzing nytimes Wordle guesses.
lazy final val letterFrequencies = Array2d[Int](
(46,615,763,839,1745,325,628,651,1011,128,573,1319,797,1123,884,726,49,1642,2241,1162,631,299,408,97,659,184),
(15,103,128,202,597,49,126,107,358,32,123,321,171,226,483,38,6,439,565,233,340,21,58,21,227,40),
(63,128,106,218,689,86,75,407,526,14,241,369,197,307,627,208,5,507,675,343,361,60,66,24,226,28),
(39,202,218,149,1257,108,183,175,634,35,140,407,212,418,692,194,10,596,763,272,409,97,184,52,348,46),
(745,597,689,1257,919,396,568,583,1214,111,504,1315,726,1083,1217,763,34,1876,2323,1223,662,437,455,199,655,187),
(25,49,86,108,396,118,75,72,295,11,68,258,58,129,248,26,7,299,415,208,205,14,50,20,151,24),
(28,126,75,183,568,75,99,141,424,24,55,324,146,416,476,129,3,423,536,206,326,48,66,4,244,28),
(51,107,407,175,583,72,141,53,399,21,145,282,198,238,488,174,6,342,715,454,285,44,158,14,207,23),
(11,358,526,634,1214,295,424,399,169,71,392,853,518,884,594,467,50,970,1471,853,335,246,215,104,323,130),
(28,32,14,35,111,11,24,21,71,2,31,41,28,52,98,26,1,45,112,33,75,9,12,1,38,3),
(73,123,241,140,504,68,55,145,392,31,61,247,102,300,376,152,8,338,744,184,240,21,86,2,224,20),
(319,321,369,407,1315,258,324,282,853,41,247,250,341,369,875,395,10,468,1237,491,566,173,201,61,463,50),
(97,171,197,212,726,58,146,198,518,28,102,341,102,257,555,195,6,429,769,273,401,33,61,40,260,44),
(123,226,307,418,1083,129,416,238,884,52,300,369,257,159,849,265,18,533,1027,537,499,113,220,45,374,65),
(84,483,627,692,1217,248,476,488,594,98,376,875,555,849,525,566,18,1096,1658,856,462,175,329,85,521,130),
(26,38,208,194,763,26,129,174,467,26,152,395,195,265,566,127,8,488,874,347,353,35,83,24,333,28),
(9,6,5,10,34,7,3,6,50,1,8,10,6,18,18,8,1,16,37,25,96,0,2,0,7,1),
(642,439,507,596,1876,299,423,342,970,45,338,468,429,533,1096,488,16,246,1461,789,673,189,234,52,491,77),
(241,565,675,763,2323,415,536,715,1471,112,744,1237,769,1027,1658,874,37,1461,717,1367,1088,221,484,86,598,105),
(162,233,343,272,1223,208,206,454,853,33,184,491,273,537,856,347,25,789,1367,254,548,72,202,49,384,52),
(31,340,361,409,662,205,326,285,335,75,240,566,401,499,462,353,96,673,1088,548,73,61,41,32,317,51),
(99,21,60,97,437,14,48,44,246,9,21,173,33,113,175,35,0,189,221,72,61,20,25,10,63,7),
(8,58,66,184,455,50,66,158,215,12,86,201,61,220,329,83,2,234,484,202,41,25,11,12,133,19),
(7,21,24,52,199,20,4,14,104,1,2,61,40,45,85,24,0,52,86,49,32,10,12,1,34,2),
(59,227,226,348,655,151,244,207,323,38,224,463,260,374,521,333,7,491,598,384,317,63,133,34,43,54),
(84,40,28,46,187,24,28,23,130,3,20,50,44,65,130,28,1,77,105,52,51,7,19,2,54,42),
)
def prettyPrintArray(): Unit = {
val alphabet = "abcdefghijklmnopqrstuvwxyz"
val toprow = alphabet.map { "%4s".format(_) }.mkString(",")
printf("// %s\n", toprow)
for (a <- alphabet){
val freqs: Seq[String] = for {
b <- alphabet
(x,y) = (alphabet.indexOf(a), alphabet.indexOf(b))
freq = letterFrequencies(x)(y)
} yield "%4d".format(freq)
printf("/* %s */ (%s),\n", a, freqs.mkString(","))
}
}
}

Related

Using the kronecker product on complex matrices with scalaNLP breeze

I had a piece of code:
def this(vectors: List[DenseVector[Double]]) {
this(vectors.length)
var resultVector = vectors.head
for (vector <- vectors) {
resultVector = kron(resultVector.toDenseMatrix, vector.toDenseMatrix).toDenseVector
}
_vector = resultVector
}
It worked just the way I wanted it to work. The problem is that I needed complex values in stead of doubles. After importing breeze.math.Complex, I changed the code to:
def this(vectors: List[DenseVector[Complex]]) {
this(vectors.length)
var resultVector = vectors.head
for (vector <- vectors) {
resultVector = kron(resultVector.toDenseMatrix, vector.toDenseMatrix).toDenseVector
}
_vector = resultVector
}
This however results into the errors:
Error:(42, 26) could not find implicit value for parameter impl: breeze.linalg.kron.Impl2[breeze.linalg.DenseMatrix[breeze.math.Complex],breeze.linalg.DenseMatrix[breeze.math.Complex],VR]
resultVector = kron(resultVector.toDenseMatrix, vector.toDenseMatrix).toDenseVector
^
Error:(42, 26) not enough arguments for method apply: (implicit impl: breeze.linalg.kron.Impl2[breeze.linalg.DenseMatrix[breeze.math.Complex],breeze.linalg.DenseMatrix[breeze.math.Complex],VR])VR in trait UFunc.
Unspecified value parameter impl.
resultVector = kron(resultVector.toDenseMatrix, vector.toDenseMatrix).toDenseVector
^
Is this a bug or am I forgetting to do something?
I found the problem in the following way:
I first rewrote the function to use less matrix conversions
As there was a problem with the implicit impl variable of kron, I also rewrote the function call to explicitly state which variable to use to use
.
def this(vectors: List[DenseVector[Complex]]) {
this(vectors.length)
var resultMatrix = vectors.head.toDenseMatrix
for (i <- 1 until vectors.length) {
resultMatrix = kron(resultMatrix, vectors(i).toDenseMatrix)(kron.kronDM_M[Complex, Complex, DenseMatrix[Complex], Complex])
}
_vector = resultMatrix.toDenseVector
}
This showed me that there was no ScalarMulOp for V2, M, DenseMatrix[RV] where M is a Matrix[V1], V1 and V2 are the input types and RV is the output type of the ScalarMulOp
Digging through the source code of breeze I found in DenseMatrixOps that there only was an implicit ScalarMulOp for the above types if V1, V2 and RV are of type Int, Long, Float and Double. By copying the function and making it specific for Complex numbers, I was able to get the kronecker product to work. Now I could also remove the explicit use of (kron.kronDM_M[Complex, Complex, DenseMatrix[Complex], Complex]). The ScalarMulOp function in question is:
implicit def s_dm_op_Complex_OpMulScalar(implicit op: OpMulScalar.Impl2[Complex, Complex, Complex]):
OpMulScalar.Impl2[Complex, DenseMatrix[Complex], DenseMatrix[Complex]] =
new OpMulScalar.Impl2[Complex, DenseMatrix[Complex], DenseMatrix[Complex]] {
def apply(b: Complex, a: DenseMatrix[Complex]): DenseMatrix[Complex] = {
val res: DenseMatrix[Complex] = DenseMatrix.zeros[Complex](a.rows, a.cols)
val resd: Array[Complex] = res.data
val ad: Array[Complex] = a.data
var c = 0
var off = 0
while (c < a.cols) {
var r = 0
while (r < a.rows) {
resd(off) = op(b, ad(a.linearIndex(r, c)))
r += 1
off += 1
}
c += 1
}
res
}
implicitly[BinaryRegistry[Complex, Matrix[Complex], OpMulScalar.type, Matrix[Complex]]].register(this)
}

How to aggregateByKey with custom class for frequency distribution?

I am trying to create a frequency distribution.
My data is in the following pattern (ColumnIndex, (Value, countOfValue)) of type (Int, (Any, Long)). For instance, (1, (A, 10)) means for column index 1, there are 10 A's.
My goal is to get the top 100 values for all my index's or Keys.
Right away I can make it less compute intensive for my workload by doing an initial filter:
val freqNumDist = numRDD.filter(x => x._2._2 > 1)
Now I found an interesting example of a class, here which seems to fit my use case:
class TopNList (val maxSize:Int) extends Serializable {
val topNCountsForColumnArray = new mutable.ArrayBuffer[(Any, Long)]
var lowestColumnCountIndex:Int = -1
var lowestValue = Long.MaxValue
def add(newValue:Any, newCount:Long): Unit = {
if (topNCountsForColumnArray.length < maxSize -1) {
topNCountsForColumnArray += ((newValue, newCount))
} else if (topNCountsForColumnArray.length == maxSize) {
updateLowestValue
} else {
if (newCount > lowestValue) {
topNCountsForColumnArray.insert(lowestColumnCountIndex, (newValue, newCount))
updateLowestValue
}
}
}
def updateLowestValue: Unit = {
var index = 0
topNCountsForColumnArray.foreach{ r =>
if (r._2 < lowestValue) {
lowestValue = r._2
lowestColumnCountIndex = index
}
index+=1
}
}
}
So Now What I was thinking was putting together an aggregateByKey to use this class in order to get my top 100 values! The problem is that I am unsure of how to use this class in aggregateByKey in order to accomplish this goal.
val initFreq:TopNList = new TopNList(100)
def freqSeq(u: (TopNList), v:(Double, Long)) = (
u.add(v._1, v._2)
)
def freqComb(u1: TopNList, u2: TopNList) = (
u2.topNCountsForColumnArray.foreach(r => u1.add(r._1, r._2))
)
val freqNumDist = numRDD.filter(x => x._2._2 > 1).aggregateByKey(initFreq)(freqSeq, freqComb)
The obvious problem is that nothing is returned by the functions I am using. So I am wondering how to modify this class or do I need to think about this in a whole new light and just cherry pick some of the functions out of this class and add them to the functions I am using for the aggregateByKey?
I'm either thinking about classes wrong or the entire aggregateByKey or both!
Your projections implementations (freqSeq, freqComb) return Unit while you expect them to return TopNList
If intentially keep the style of your solution, the relevant impl should be
def freqSeq(u: TopNList, v:(Any, Long)) : TopNList = {
u.add(v._1, v._2) // operation gives void result (Unit)
u // this one of TopNList type
}
def freqComb(u1: TopNList, u2: TopNList) : TopNList = {
u2.topNCountsForColumnArray.foreach (r => u1.add (r._1, r._2) )
u1
}
Just take a look on aggregateByKey signature of PairRDDFunctions, what does it expect for
def aggregateByKey[U](zeroValue : U)(seqOp : scala.Function2[U, V, U], combOp : scala.Function2[U, U, U])(implicit evidence$3 : scala.reflect.ClassTag[U]) : org.apache.spark.rdd.RDD[scala.Tuple2[K, U]] = { /* compiled code */ }

Type mismatch from partition in Scala (expected (Set[String]...), actual (Set[String]...) )

I have a partition method that creates tuple of two sets of string.
def partition(i:Int) = {
dictionary.keySet.partition(dictionary(_)(i) == true)
}
I also have a map that maps integer to the return value from the partition method.
val m = Map[Int, (Set[String], Set[String])]()
for (i <- Range(0, getMaxIndex())) {
m(i) = partition(i)
}
The issue is that I have type mismatch error, but the error message does not make sense to me.
What might be wrong?
This is the code:
import scala.collection.mutable.Map
import scala.collection.{BitSet}
case class Partition(dictionary:Map[String, BitSet]) {
def max(x:Int, y:Int) = if (x > y) x else y
def partition(i:Int) = {
dictionary.keySet.partition(dictionary(_)(i) == true)
}
def getMaxIndex() = {
val values = dictionary.values
(0 /: values) ((m, bs) => max(m, bs.last))
}
def get() = {
val m = Map[Int, (Set[String], Set[String])]()
for (i <- Range(0, getMaxIndex())) {
m(i) = partition(i)
}
m
}
}
When I compile your example, the error is clear:
<console>:64: error: type mismatch;
found : (scala.collection.Set[String], scala.collection.Set[String])
required: (scala.collection.immutable.Set[String], scala.collection.immutable.Set[String])
m(i) = partition(i)
^
Looking into the API, the keySet method of a mutable map does not guarantee that the returned set is immutable. Compare this with keySet on an immutable Map—it does indeed return an immutable set.
Therefore, you could either
use an immutable Map and a var
force the result of your partition method to return an immutable set (e.g. toSet)
define the value type of your map to be collection.Set instead of Predef.Set which is an alias for collection.immtuable.Set.
To clarify these types, it helps to specify an explicit return type for your public methods (get and partition)

How to add 'Array[Ordered[Any]]' as a method parameter

Below is an implementation of Selection sort written in Scala.
The line ss.sort(arr) causes this error :
type mismatch; found : Array[String] required: Array[Ordered[Any]]
Since the type Ordered is inherited by StringOps should this type not be inferred ?
How can I add the array of Strings to sort() method ?
Here is the complete code :
object SelectionSortTest {
def main(args: Array[String]){
val arr = Array("Hello","World")
val ss = new SelectionSort()
ss.sort(arr)
}
}
class SelectionSort {
def sort(a : Array[Ordered[Any]]) = {
var N = a.length
for (i <- 0 until N) {
var min = i
for(j <- i + 1 until N){
if( less(a(j) , a(min))){
min = j
}
exchange(a , i , min)
}
}
}
def less(v : Ordered[Any] , w : Ordered[Any]) = {
v.compareTo(w) < 0
}
def exchange(a : Array[Ordered[Any]] , i : Integer , j : Integer) = {
var swap : Ordered[Any] = a(i)
a(i) = a(j)
a(j) = swap
}
}
Array is invariant. You cannot use an Array[A] as an Array[B] even if A is subtype of B. See here why: Why are Arrays invariant, but Lists covariant?
Neither is Ordered, so your implementation of less will not work either.
You should make your implementation generic the following way:
object SelectionSortTest {
def main(args: Array[String]){
val arr = Array("Hello","World")
val ss = new SelectionSort()
ss.sort(arr)
}
}
class SelectionSort {
def sort[T <% Ordered[T]](a : Array[T]) = {
var N = a.length
for (i <- 0 until N) {
var min = i
for(j <- i + 1 until N){
if(a(j) < a(min)){ // call less directly on Ordered[T]
min = j
}
exchange(a , i , min)
}
}
}
def exchange[T](a : Array[T] , i : Integer , j : Integer) = {
var swap = a(i)
a(i) = a(j)
a(j) = swap
}
}
The somewhat bizarre statement T <% Ordered[T] means "any type T that can be implicitly converted to Ordered[T]". This ensures that you can still use the less-than operator.
See this for details:
What are Scala context and view bounds?
The answer by #gzm0 (with some very nice links) suggests Ordered. I'm going to complement with an answer covering Ordering, which provides equivalent functionality without imposing on your classes as much.
Let's adjust the sort method to accept an array of type 'T' for which an Ordering implicit instance is defined.
def sort[T : Ordering](a: Array[T]) = {
val ord = implicitly[Ordering[T]]
import ord._ // now comparison operations such as '<' are available for 'T'
// ...
if (a(j) < a(min))
// ...
}
The [T : Ordering] and implicitly[Ordering[T]] combo is equivalent to an implicit parameter of type Ordering[T]:
def sort[T](a: Array[T])(implicit ord: Ordering[T]) = {
import ord._
// ...
}
Why is this useful?
Imagine you are provided with a case class Account(balance: Int) by some third party. You can now add an Ordering for it like so:
// somewhere in scope
implicit val accountOrdering = new Ordering[Account] {
def compare(x: Account, y: Account) = x.balance - y.balance
}
// or, more simply
implicit val accountOrdering: Ordering[Account] = Ordering by (_.balance)
As long as that instance is in scope, you should be able to use sort(accounts).
If you want to use some different ordering, you can also provide it explicitly, like so: sort(accounts)(otherOrdering).
Note that this isn't very different from providing an implicit conversion to Ordering (at least not within the context of this question).
Even though, when coding Scala, I'm used to prefer functional programming style (via combinators or recursion) over imperative style (via variables and iterations), THIS TIME, for this specific problem, old school imperative nested loops result in simpler and performant code.
I don't think falling back to imperative style is a mistake for certain classes of problems, such as sorting algorithms which usually transform the input buffer (more like a procedure) rather than resulting to a new sorted collection.
Here it is my solution:
package bitspoke.algo
import scala.math.Ordered
import scala.collection.mutable.Buffer
abstract class Sorter[T <% Ordered[T]] {
// algorithm provided by subclasses
def sort(buffer : Buffer[T]) : Unit
// check if the buffer is sorted
def sorted(buffer : Buffer[T]) = buffer.isEmpty || buffer.view.zip(buffer.tail).forall { t => t._2 > t._1 }
// swap elements in buffer
def swap(buffer : Buffer[T], i:Int, j:Int) {
val temp = buffer(i)
buffer(i) = buffer(j)
buffer(j) = temp
}
}
class SelectionSorter[T <% Ordered[T]] extends Sorter[T] {
def sort(buffer : Buffer[T]) : Unit = {
for (i <- 0 until buffer.length) {
var min = i
for (j <- i until buffer.length) {
if (buffer(j) < buffer(min))
min = j
}
swap(buffer, i, min)
}
}
}
As you can see, to achieve parametric polymorphism, rather than using java.lang.Comparable, I preferred scala.math.Ordered and Scala View Bounds rather than Upper Bounds. That's certainly works thanks to Scala Implicit Conversions of primitive types to Rich Wrappers.
You can write a client program as follows:
import bitspoke.algo._
import scala.collection.mutable._
val sorter = new SelectionSorter[Int]
val buffer = ArrayBuffer(3, 0, 4, 2, 1)
sorter.sort(buffer)
assert(sorter.sorted(buffer))

Selection Sort Generic type implementation

I worked my way implementing a recursive version of selection and quick sort,i am trying to modify the code in a way that it can sort a list of any generic type , i want to assume that the generic type supplied can be converted to Comparable at runtime.
Does anyone have a link ,code or tutorial on how to do this please
I am trying to modify this particular code
'def main (args:Array[String]){
val l = List(2,4,5,6,8)
print(quickSort(l))
}
def quickSort(x:List[Int]):List[Int]={
x match{
case xh::xt =>
{
val (first,pivot,second) = partition(x)
quickSort (first):::(pivot :: quickSort(second))
}
case Nil => {x}
}
}
def partition (x:List[Int])=
{
val pivot =x.head
var first:List[Int]=List ()
var second : List[Int]=List ()
val fun=(i:Int)=> {
if (i<pivot)
first=i::first
else
second=i::second
}
x.tail.foreach(fun)
(first,pivot,second)
}
enter code here
def main (args:Array[String]){
val l = List(2,4,5,6,8)
print(quickSort(l))
}
def quickSort(x:List[Int]):List[Int]={
x match{
case xh::xt =>
{
val (first,pivot,second) = partition(x)
quickSort (first):::(pivot :: quickSort(second))
}
case Nil => {x}
}
}
def partition (x:List[Int])=
{
val pivot =x.head
var first:List[Int]=List ()
var second : List[Int]=List ()
val fun=(i:Int)=> {
if (i<pivot)
first=i::first
else
second=i::second
}
x.tail.foreach(fun)
(first,pivot,second)
} '
Language: SCALA
In Scala, Java Comparator is replaced by Ordering (quite similar but comes with more useful methods). They are implemented for several types (primitives, strings, bigDecimals, etc.) and you can provide your own implementations.
You can then use scala implicit to ask the compiler to pick the correct one for you:
def sort[A]( lst: List[A] )( implicit ord: Ordering[A] ) = {
...
}
If you are using a predefined ordering, just call:
sort( myLst )
and the compiler will infer the second argument. If you want to declare your own ordering, use the keyword implicit in the declaration. For instance:
implicit val fooOrdering = new Ordering[Foo] {
def compare( f1: Foo, f2: Foo ) = {...}
}
and it will be implicitly use if you try to sort a List of Foo.
If you have several implementations for the same type, you can also explicitly pass the correct ordering object:
sort( myFooLst )( fooOrdering )
More info in this post.
For Quicksort, I'll modify an example from the "Scala By Example" book to make it more generic.
class Quicksort[A <% Ordered[A]] {
def sort(a:ArraySeq[A]): ArraySeq[A] =
if (a.length < 2) a
else {
val pivot = a(a.length / 2)
sort (a filter (pivot >)) ++ (a filter (pivot == )) ++
sort (a filter(pivot <))
}
}
Test with Int
scala> val quicksort = new Quicksort[Int]
quicksort: Quicksort[Int] = Quicksort#38ceb62f
scala> val a = ArraySeq(5, 3, 2, 2, 1, 1, 9, 39 ,219)
a: scala.collection.mutable.ArraySeq[Int] = ArraySeq(5, 3, 2, 2, 1, 1, 9, 39, 21
9)
scala> quicksort.sort(a).foreach(n=> (print(n), print (" " )))
1 1 2 2 3 5 9 39 219
Test with a custom class implementing Ordered
scala> case class Meh(x: Int, y:Int) extends Ordered[Meh] {
| def compare(that: Meh) = (x + y).compare(that.x + that.y)
| }
defined class Meh
scala> val q2 = new Quicksort[Meh]
q2: Quicksort[Meh] = Quicksort#7677ce29
scala> val a3 = ArraySeq(Meh(1,1), Meh(12,1), Meh(0,1), Meh(2,2))
a3: scala.collection.mutable.ArraySeq[Meh] = ArraySeq(Meh(1,1), Meh(12,1), Meh(0
,1), Meh(2,2))
scala> q2.sort(a3)
res7: scala.collection.mutable.ArraySeq[Meh] = ArraySeq(Meh(0,1), Meh(1,1), Meh(
2,2), Meh(12,1))
Even though, when coding Scala, I'm used to prefer functional programming style (via combinators or recursion) over imperative style (via variables and iterations), THIS TIME, for this specific problem, old school imperative nested loops result in simpler code for the reader. I don't think falling back to imperative style is a mistake for certain classes of problems (such as sorting algorithms which usually transform the input buffer (like a procedure) rather than resulting to a new sorted one
Here it is my solution:
package bitspoke.algo
import scala.math.Ordered
import scala.collection.mutable.Buffer
abstract class Sorter[T <% Ordered[T]] {
// algorithm provided by subclasses
def sort(buffer : Buffer[T]) : Unit
// check if the buffer is sorted
def sorted(buffer : Buffer[T]) = buffer.isEmpty || buffer.view.zip(buffer.tail).forall { t => t._2 > t._1 }
// swap elements in buffer
def swap(buffer : Buffer[T], i:Int, j:Int) {
val temp = buffer(i)
buffer(i) = buffer(j)
buffer(j) = temp
}
}
class SelectionSorter[T <% Ordered[T]] extends Sorter[T] {
def sort(buffer : Buffer[T]) : Unit = {
for (i <- 0 until buffer.length) {
var min = i
for (j <- i until buffer.length) {
if (buffer(j) < buffer(min))
min = j
}
swap(buffer, i, min)
}
}
}
As you can see, rather than using java.lang.Comparable, I preferred scala.math.Ordered and Scala View Bounds rather than Upper Bounds. That's certainly works thanks to many Scala Implicit Conversions of primitive types to Rich Wrappers.
You can write a client program as follows:
import bitspoke.algo._
import scala.collection.mutable._
val sorter = new SelectionSorter[Int]
val buffer = ArrayBuffer(3, 0, 4, 2, 1)
sorter.sort(buffer)
assert(sorter.sorted(buffer))