Scala: How to sort an array within a specified range of indices? - scala

And I have a comparison function "compr" already in the code to compare two values.
I want something like this:
Sorting.stableSort(arr[i,j] , compr)
where arr[i,j] is a range of element in array.

Take the slice as a view, sort and copy it back (or take a slice as a working buffer).
scala> val vs = Array(3,2,8,5,4,9,1,10,6,7)
vs: Array[Int] = Array(3, 2, 8, 5, 4, 9, 1, 10, 6, 7)
scala> vs.view(2,5).toSeq.sorted.copyToArray(vs,2)
scala> vs
res31: Array[Int] = Array(3, 2, 4, 5, 8, 9, 1, 10, 6, 7)
Outside the REPL, the extra .toSeq isn't needed:
vs.view(2,5).sorted.copyToArray(vs,2)
Updated:
scala 2.13.8> val vs = Array(3, 2, 8, 5, 4, 9, 1, 10, 6, 7)
val vs: Array[Int] = Array(3, 2, 8, 5, 4, 9, 1, 10, 6, 7)
scala 2.13.8> vs.view.slice(2,5).sorted.copyToArray(vs,2)
val res0: Int = 3
scala 2.13.8> vs
val res1: Array[Int] = Array(3, 2, 4, 5, 8, 9, 1, 10, 6, 7)

Split array into three parts, sort middle part and then concat them, not the most efficient way, but this is FP who cares about performance =)
val sorted =
for {
first <- l.take(FROM)
sortingPart <- l.slice(FROM, UNTIL)
lastPart <- l.takeRight(UNTIL)
} yield (first ++ Sorter.sort(sortingPart) ++ lastPart)

Something like that:
def stableSort[T](x: Seq[T], i: Int, j: Int, comp: (T,T) => Boolean ):Seq[T] = {
x.take(i) ++ x.slice(i,j).sortWith(comp) ++ x.drop(i+j-1)
}
def comp: (Int,Int) => Boolean = { case (x1,x2) => x1 < x2 }
val x = Array(1,9,5,6,3)
stableSort(x,1,4, comp)
// > res0: Seq[Int] = ArrayBuffer(1, 5, 6, 9, 3)
If your class implements Ordering it would be less cumbersome.

This should be as good as you can get without reimplementing the sort. Creates just one extra array with the size of the slice to be sorted.
def stableSort[K:reflect.ClassTag](xs:Array[K], from:Int, to:Int, comp:(K,K) => Boolean) : Unit = {
val tmp = xs.slice(from,to)
scala.util.Sorting.stableSort(tmp, comp)
tmp.copyToArray(xs, from)
}

Related

Scala -- List into List of Count and List of Element

Let's say I have Scala list like this:
val mylist = List(4,2,5,6,4,4,2,6,5,6,6,2,5,4,4)
How can I transform it into list of count and list of element? For example, I want to convert mylist into:
val count = List(3,5,3,4)
val elements = List(2,4,5,6)
Which means, in mylist, I have three occurrences of 2, five occurrences of 4, etc.
In procedural, this is easy as I can just make two empty lists (for count and elements) and fill them while doing iteration. However, I have no idea on how to achieve this in Scala.
Arguably a shortest version:
val elements = mylist.distinct
val count = elements map (e => mylist.count(_ == e))
Use .groupBy(identity) to create a Map regrouping elements with their occurences:
scala> val mylist = List(4,2,5,6,4,4,2,6,5,6,6,2,5,4,4)
mylist: List[Int] = List(4, 2, 5, 6, 4, 4, 2, 6, 5, 6, 6, 2, 5, 4, 4)
scala> mylist.groupBy(identity)
res0: scala.collection.immutable.Map[Int,List[Int]] = Map(2 -> List(2, 2, 2), 5 -> List(5, 5, 5), 4 -> List(4, 4, 4, 4, 4), 6 -> List(6, 6, 6, 6))
Then you can use .mapValues(_.length) to change the 'value' part of the map to the size of the list:
scala> mylist.groupBy(identity).mapValues(_.length)
res1: scala.collection.immutable.Map[Int,Int] = Map(2 -> 3, 5 -> 3, 4 -> 5, 6 -> 4)
If you want to get 2 lists out of this you can use .unzip, which returns a tuple, the first part being the keys (ie the elements), the second being the values (ie the number of instances of the element in the original list):
scala> val (elements, counts) = mylist.groupBy(identity).mapValues(_.length).unzip
elements: scala.collection.immutable.Iterable[Int] = List(2, 5, 4, 6)
counts: scala.collection.immutable.Iterable[Int] = List(3, 3, 5, 4)
One way would be to use groupBy and then check the size of each "group":
val withSizes = mylist.groupBy(identity).toList.map { case (v, l) => (v, l.size) }
val count = withSizes.map(_._2)
val elements = withSizes.map(_._1)
You can try like this as well alternative way of doing the same.
Step - 1
scala> val mylist = List(4,2,5,6,4,4,2,6,5,6,6,2,5,4,4)
mylist: List[Int] = List(4, 2, 5, 6, 4, 4, 2, 6, 5, 6, 6, 2, 5, 4, 4)
// Use groupBy { x => x } returns a "Map[Int, List[Int]]"
step - 2
scala> mylist.groupBy(x => (x))
res0: scala.collection.immutable.Map[Int,List[Int]] = Map(2 -> List(2, 2, 2), 5 -> List(5, 5, 5), 4 -> List(4, 4, 4, 4, 4), 6 -> List(6, 6, 6, 6))
step - 3
scala> mylist.groupBy(x => (x)).map{case(num,times) =>(num,times.size)}.toList
res1: List[(Int, Int)] = List((2,3), (5,3), (4,5), (6,4))
step -4 - sort by num
scala> mylist.groupBy(x => (x)).map{case(num,times) =>(num,times.size)}.toList.sortBy(_._1)
res2: List[(Int, Int)] = List((2,3), (4,5), (5,3), (6,4))
step -5 - unzip to beak into to list it return tuple
scala> mylist.groupBy(x => (x)).map{case(num,times) =>(num,times.size)}.toList.sortBy(_._1).unzip
res3: (List[Int], List[Int]) = (List(2, 4, 5, 6),List(3, 5, 3, 4))

How to split a collection into groups using the calculation of member as a predicate

I have a method that collect the consecutive number with the difference of no more than some number (2 in my example). This code is working just fine but it does zipping every time it is called, so I wonder if there is any better solution to this thanks.
def myGrouper(sortedData: Seq[Int], maxDif: Int): Seq[Seq[Int]] = sortedData match {
case Nil => Nil
case _ =>
val (grouped, rest) = sortedData.zipWithIndex.span{
case (num, idx) =>
if (idx > 1) Math.abs(sortedData(idx-1) - num) <= maxDif
else true
}
Seq(grouped.map(_._1)) ++ myGrouper(rest.map(_._1), maxDif)
}
val myList = Seq(1, 2, 3, 7, 8, 10, 15, 17, 19)
val maxDif = 2
println(myGrouper(myList, maxDif))
Below is the result from running this code
myList: Seq[Int] = List(1, 2, 3, 7, 8, 10, 15, 17, 19)
maxDif: Int = 2
List(List(1, 2, 3), List(7, 8, 10), List(15, 17, 19))
res0: Unit = ()

Removing an element from MutableList in Scala

I have a MutableList and I want to remove an element from it but I cannot find the appropriate method. There is a method to remove element from ListBuffer like this:
val x = ListBuffer(1, 2, 3, 4, 5, 6, 7, 8, 9)
x -= 5
I am unable to find an equivalent method on MutableList.
MutableList lacks -= and --= because it does not extend the Shrinkable trait. Various motivations for this can be found here.
MutableList does have diff, filter, and other methods which can help you in case you are in a situation where reassigning a variable (or instantiating a new variable) might be an option, and performance concerns aren't paramount:
var mylist = MutableList(1, 2, 3)
mylist = mylist diff Seq(1)
val myNewList = mylist.filter(_ != 2)
val indexFiltered = mylist.zipWithIndex.collect { case (el, ind) if ind != 1 => el }
You can often use ListBuffer instead of MutableList, which will unlock the desired -= and --= methods:
val mylist = ListBuffer(1, 2, 3)
mylist -= 1 //mylist is now ListBuffer(2, 3)
mylist --= Seq(2, 3) //mylist is now empty
It's not the answer, just to warn you about problems (at least in 2.11.x):
//street magic
scala> val a = mutable.MutableList(1,2,3)
a: scala.collection.mutable.MutableList[Int] = MutableList(1, 2, 3)
scala> a += 4
res7: a.type = MutableList(1, 2, 3, 4)
scala> a
res8: scala.collection.mutable.MutableList[Int] = MutableList(1, 2, 3, 4)
scala> a ++= List(8,9,10)
res9: a.type = MutableList(1, 2, 3, 4, 8, 9, 10)
scala> val b = a.tail
b: scala.collection.mutable.MutableList[Int] = MutableList(2, 3, 4, 8, 9, 10)
scala> b.length
res10: Int = 6
scala> a.length
res11: Int = 7
scala> a ++= List(8,9,10)
res12: a.type = MutableList(1, 2, 3, 4, 8, 9, 10, 8, 9, 10)
scala> b += 7
res13: b.type = MutableList(2, 3, 4, 8, 9, 10, 7)
scala> a
res14: scala.collection.mutable.MutableList[Int] = MutableList(1, 2, 3, 4, 8, 9, 10, 7)
scala> b
res15: scala.collection.mutable.MutableList[Int] = MutableList(2, 3, 4, 8, 9, 10, 7)
scala> a ++= List(8,9,10)
res16: a.type = MutableList(1, 2, 3, 4, 8, 9, 10, 7)
This example is taken from some gist - I've posted it on facebook with #devid_blein #street_magic tags, but can't find original link on the internet.

Can we call method having more than one arguments with list.map?

I was trying to perform multiply operation on list in Scala like:
val list = List(1,2,3,4,5)
list.map(_*2)
res0: List[Int] = List(2, 4, 6, 8, 10) // Output
Now, I have created a separate method for the multiply operation like:
val list = List(1,2,3,4,5)
def multiplyListContents(x: Int) = {
x * 2
}
list.map(multiplyListContents)
res1: List[Int] = List(2, 4, 6, 8, 10) // Output
Now I want to pass custom multiplier instead of using default multiplier 2 like:
val list = List(1,2,3,4,5)
val multiplier = 3
def multiplyListContents(x: Int, multiplier: Int) = {
x * multiplier
}
list.map(multiplyListContents(multiplier))
res1: List[Int] = List(3, 6, 9, 12, 15) // Output should be this
Any idea how to do this?
scala> list.map(multiplyListContents(_, multiplier))
res0: List[Int] = List(3, 6, 9, 12, 15)
This translates to list.map(x => multiplyListContents(x, multiplier)).
(see scala placeholder syntax for more information).

Scala trying to count instances of a digit in a number

This is my first day using scala. I am trying to make a string of the number of times each digit is represented in a string. For instance, the number 4310227 would return "1121100100" because 0 appears once, 1 appears once, 2 appears twice and so on...
def pow(n:Int) : String = {
val cubed = (n * n * n).toString
val digits = 0 to 9
val str = ""
for (a <- digits) {
println(a)
val b = cubed.count(_==a.toString)
println(b)
}
return cubed
}
and it doesn't seem to work. would like some scalay reasons why and to know whether I should even be going about it in this manner. Thanks!
When you iterate over strings, which is what you are doing when you call String#count(), you are working with Chars, not Strings. You don't want to compare these two with ==, since they aren't the same type of object.
One way to solve this problem is to call Char#toString() before performing the comparison, e.g., amend your code to read cubed.count(_.toString==a.toString).
As Rado and cheeken said, you're comparing a Char with a String, which will never be be equal. An alternative to cheekin's answer of converting each character to a string is to create a range from chars, ie '0' to '9':
val digits = '0' to '9'
...
val b = cubed.count(_ == a)
Note that if you want the Int that a Char represents, you can call char.asDigit.
Aleksey's, Ren's and Randall's answers are something you will want to strive towards as they separate out the pure solution to the problem. However, given that it's your first day with Scala, depending on what background you have, you might need a bit more context before understanding them.
Fairly simple:
scala> ("122333abc456xyz" filter (_.isDigit)).foldLeft(Map.empty[Char, Int]) ((histo, c) => histo + (c -> (histo.getOrElse(c, 0) + 1)))
res1: scala.collection.immutable.Map[Char,Int] = Map(4 -> 1, 5 -> 1, 6 -> 1, 1 -> 1, 2 -> 2, 3 -> 3)
This is perhaps not the fastest approach because intermediate datatype like String and Char are used but one of the most simplest:
def countDigits(n: Int): Map[Int, Int] =
n.toString.groupBy(x => x) map { case (n, c) => (n.asDigit, c.size) }
Example:
scala> def countDigits(n: Int): Map[Int, Int] = n.toString.groupBy(x => x) map { case (n, c) => (n.asDigit, c.size) }
countDigits: (n: Int)Map[Int,Int]
scala> countDigits(12345135)
res0: Map[Int,Int] = Map(5 -> 2, 1 -> 2, 2 -> 1, 3 -> 2, 4 -> 1)
Where myNumAsString is a String, eg "15625"
myNumAsString.groupBy(x => x).map(x => (x._1, x._2.length))
Result = Map(2 -> 1, 5 -> 2, 1 -> 1, 6 -> 1)
ie. A map containing the digit with its corresponding count.
What this is doing is taking your list, grouping the values by value (So for the initial string of "15625", it produces a map of 1 -> 1, 2 -> 2, 6 -> 6, and 5 -> 55.). The second bit just creates a map of the value to the count of how many times it occurs.
The counts for these hundred digits happen to fit into a hex digit.
scala> val is = for (_ <- (1 to 100).toList) yield r.nextInt(10)
is: List[Int] = List(8, 3, 9, 8, 0, 2, 0, 7, 8, 1, 6, 9, 9, 0, 3, 6, 8, 6, 3, 1, 8, 7, 0, 4, 4, 8, 4, 6, 9, 7, 4, 6, 6, 0, 3, 0, 4, 1, 5, 8, 9, 1, 2, 0, 8, 8, 2, 3, 8, 6, 4, 7, 1, 0, 2, 2, 6, 9, 3, 8, 6, 7, 9, 5, 0, 7, 6, 8, 7, 5, 8, 2, 2, 2, 4, 1, 2, 2, 6, 8, 1, 7, 0, 7, 6, 9, 5, 5, 5, 3, 5, 8, 2, 5, 1, 9, 5, 7, 2, 3)
scala> (new Array[Int](10) /: is) { case (a, i) => a(i) += 1 ; a } map ("%x" format _) mkString
warning: there were 1 feature warning(s); re-run with -feature for details
res7: String = a8c879caf9
scala> (new Array[Int](10) /: is) { case (a, i) => a(i) += 1 ; a } sum
warning: there were 1 feature warning(s); re-run with -feature for details
res8: Int = 100
I was going to point out that no one used a char range, but now I see Kristian did.
def pow(n:Int) : String = {
val cubed = (n * n * n).toString
val cnts = for (a <- '0' to '9') yield cubed.count(_ == a)
(cnts map (c => ('0' + c).toChar)).mkString
}