Scala trying to count instances of a digit in a number - scala

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
}

Related

Scala - Calculate maximum average between two lists

I am at the beginning of my Scala journey. I am trying to find and compare the average value of a given dataset - type Map(String, List[Int]), for two random rows selected by the user, in order to return the greater average value between the two. I can calculate the average for each row but I can't find a way to compare the average between the two rows.
I have tried in different ways, but I only get error messages. However the program calculates the average of each row
DATASET
SK1, 9, 7, 2, 0, 7, 3, 7, 9, 1, 2, 8, 1, 9, 6, 5, 3, 2, 2, 7, 2, 8, 5, 4, 5, 1, 6, 5, 2, 4, 1
SK2, 0, 7, 6, 3, 3, 3, 1, 6, 9, 2, 9, 7, 8, 7, 3, 6, 3, 5, 5, 2, 9, 7, 3, 4, 6, 3, 4, 3, 4, 1
SK3, 8, 7, 1, 8, 0, 5, 8, 3, 5, 9, 7, 5, 4, 7, 9, 8, 1, 4, 6, 5, 6, 6, 3, 6, 8, 8, 7, 4, 0, 6
This is how I the program calculates the average of a row
//Function to find the average
def average(list: List[Int]): Double = list.sum.toDouble / list.size
def averageStockLevel1(stock1: String, stock2: String): (String, Int) = {
val ave1 = mapdata.get(stock1).map(average(_).toInt).getOrElse(0)
val ave2 = mapdata.get(stock2).map(average(_).toInt).getOrElse(0)
if (ave1>ave2){
(stock1,ave1)
}else{
(stock2,ave2)
}
}
This is how I have called the function in the menu
def handleFour(): Boolean = {
menuDoubleDataStock(averageStockLevel1)
true
}
//Pull two rows from the dataset
def menuShowDoubleDataStock(f: (String) => (String, Int), g:(String) => (String, Int)) = {
print("Please insert the Stock > ")
val data = f(readLine)
println(s"${data._1}: ${data._2}")
print("Please insert the Stock > ")
val data1 = g(readLine)
println(s"${data1._1}: ${data1._2}")
}
error message
Unspecified value parameters: g: String => (String, Int)
The error message "Unspecified value parameters: g: String => (String, Int)" tells you the following:
Your menuShowDoubleDataStock expects two parameters (f and g), but where you call it (from handleFour()), you only pass one value (averageStockLevel1) - that value is accepted as f, so the compiler complains that no value was passed for g.
Besides that specific error that the compiler currently complains about, there is also a second problem (which currently seems to be overshadowed by the one above): the type of f is defined as String => (String, Int) (a function that takes one String parameter), but the value that you are passing (averageStockLevel1) has the type (String, String) => (String, Int) (a function that takes two String parameters).
I'm not 100% sure if I understood what you are aiming to do, but I think the solution could be to change the signature of menuShowDoubleDataStock so that it only takes one parameter of type (String, String) => (String, Int):
// make the user enter two stock-names and pass them into resultCalculator to
// get the result (and then print it)
def menuShowDoubleDataStock(resultCalculator: (String, String) => (String, Int)) = {
print("Please insert the Stock > ")
val stockName1 = readLine
print("Please insert the Stock > ")
val stockName2 = readLine
val result = resultCalculator(stockName1, stockName2)
println(s"${result._1}: ${result._2}")
}
Then calling menuDoubleDataStock(averageStockLevel1) should work.

How do i concat the Int or Long to a List in Scala? [duplicate]

This question already has an answer here:
How to add data to a TrieMap[Long,List[Long]] in Scala
(1 answer)
Closed 5 years ago.
I have this:
val vertexIdListPartitions: TrieMap[Long, List[Long]]
I need to have something like this:
vertexIdListPartitions(0) -> List[2,3,4,5,etc..]
But when I add numbers in the list in this way:
for(c<- 0 to 10)
vertexIdListPartitions.update(0,List(c))
The result is List[10]
How can I concat them?
If I understand your question right, you don't need a for loop:
import scala.collection.concurrent.TrieMap
val vertexIdListPartitions = TrieMap[Long, List[Long]]()
vertexIdListPartitions.update(0, (0L to 10L).toList)
// res1: scala.collection.concurrent.TrieMap[Long,List[Long]] =
// TrieMap(0 -> List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
[UPDATE]
Below is a method for adding or concatenating a key-value tuple to the TrieMap accordingly:
def concatTM( tm: TrieMap[Long, List[Long]], kv: Tuple2[Long, List[Long]] ) =
tm += ( tm.get(kv._1) match {
case Some(l: List[Long]) => (kv._1 -> (l ::: kv._2))
case None => kv
} )
concatTM( vertexIdListPartitions, (1L, List(1L, 2L, 3L)) )
// res2: scala.collection.concurrent.TrieMap[Long,List[Long]] =
// TrieMap(0 -> List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 1 -> List(1, 2, 3))
concatTM( vertexIdListPartitions, (0L, List(11L, 12L)) )
// res61: scala.collection.concurrent.TrieMap[Long,List[Long]] =
// TrieMap(0 -> List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), 1 -> List(1, 2, 3))

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

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

Scala: Using span with modular arithmetic

I have a List[Int] from 1 to 10 and want to make a List[List[Int]] containing two List[Int]: one list containing even numbers and the other containing odd numbers. The result should be like this:
List(List(2,4,6,8,10),List(1,3,5,7,9))
I tried these things:
1.to(10).toList.span((x:Int) => x % 2 == 0)
and
val lst = 1.to(10).toList; lst span (_%2==0)
However, neither of these worked.
Can someone help me on this matter?
The method you need to use is partition, not span:
scala> (1 to 10).partition(_ % 2 == 0)
res0: (IndexedSeq[Int], IndexedSeq[Int]) = (Vector(2, 4, 6, 8, 10),Vector(1, 3, 5, 7, 9))
Since you want a List[List[Int]], you could do this:
val lst = (1 to 10).toList
val (evens, odds) = lst.partition(_ % 2 == 0)
val newList = List(evens,odds) // List(List(2, 4, 6, 8, 10), List(1, 3, 5, 7, 9))
The span method can only be used to split a sequence at a single point:
scala> (1 to 10).span(_ < 5)
res1: (Range, Range) = (Range(1, 2, 3, 4),Range(5, 6, 7, 8, 9, 10))
When you tried lst.span(_ % 2 == 0), the program found that the first item, 1, did not pass the test (_ % 2 == 0), so all the elements were put in the second list, leaving none in the first.

How to compare a list element with the next element, to yield this element?

As I noted in the title, how to compare the element of index N with element of index N+1, if elements compared are exactly the same, yield element only once.
I know I can use toSet, to get a set of unique elements, but this does not help me because, my list can contain duplicated elements but duplicated element can't be the next element in my list.
val ll = List(1, 2, 3, 6, 3, 7, 5, 5, 6, 3)
// Desired output: List(1, 2, 3, 6, 3, 7, 5, 6, 3)
I got a "near working solution" using zipWithIndex.collect, but when I compare inside it, index runs OutOfBounds. I can make this to work if I can use two conditions inside, first check maximum index to be index = (list.size-1) then I can compare list(index) != list(index+1) then yield list(index)
What I have tried without success (because of OutOfBounds), is:
times.zipWithIndex.collect
{
case (element, index)
// index+1 will be incremented out of my list
if (times(index) != times(index+1)) => times(index)
}
This can work if I can use one more condition to limit index, but does not work with two conditions:
times.zipWithIndex.collect
{
case (element, index)
if (index < times.size)
if (times(index) != times(index+1)) => times(index)
}
I appreciate any kind of alternative.
how about
ll.foldLeft(List[Int]())((acc, x) => acc match {case Nil => List(x) case y => if (y.last == x) y else y :+ x})
Here's my alternative using the sliding function:
val ll = List(1, 2, 3, 6, 3, 7, 5, 5, 6, 3)
ll.sliding(2)
.filter( t => t.length > 1 && t(0) != t(1) )
.map( t => t(0) )
.toList :+ ll.last
You can use zip the list with itself, dropping the first element so that you compare elements at index N with N + 1. You only need to append the last element (you may want to use a ListBuffer as appending the last element requires to copy the list).
val r = times.zip(times.drop(1)).withFilter(t => t._1 != t._2).map(_._1) :+ times.last
scala> val times = List(1, 2, 3, 6, 3, 7, 5, 5, 6, 3)
times: List[Int] = List(1, 2, 3, 6, 3, 7, 5, 5, 6, 3)
scala> val r = times.zip(times.drop(1)).withFilter(t => t._1 != t._2).map(_._1) :+ times.last
r: List[Int] = List(1, 2, 3, 6, 3, 7, 5, 6, 3)