Currently my system has the ability for a user to enter 2 numbers, the last number on the tail is found and returned, how can I get the data and data2 to only show there numbers, not the SK1/SK3 before. Currently I am getting the error ;
Error:(177, 28) value >= is not a member of (String, Int)
val highest = if (data >= data2){
//Compare 2 values
def mnuCompareTwoStocks(f: (String) => (String, Int)) = {
print("Stock > ")
val data = f(readLine)
print("Stock 2 > ")
val data2 = f(readLine)
val highest = if (data >= data2){
println(data)
}
else
{
println(data2)
}
println(s"${data._1}: ${data._2} ${data2._1}: ${data2._2}")
}
EDIT:
The working outcome
//Compare 2 values
def mnuCompareTwoStocks(f: (String) => (String, Int)) = {
print("Stock > ")
val data = f(readLine)
print("Stock 2 > ")
val data2 = f(readLine)
if (data._2 >= data2._2){
println("The higher stock is " + data)
}
else
{
println("The higher stock is " + data2)
}
println(s"${data._1}: ${data._2} ${data2._1}: ${data2._2}")
}
You are trying to compare 2 tuples of type (String,Int). There is no simple comparison operator for such.
scala> ("a",3) > ("b",0)
<console>:12: error: value > is not a member of (String, Int)
("a",3) > ("b",0)
^
Do you want the String to take precedence or the Int?
scala> ("a",3)._1 > ("b",0)._1
res0: Boolean = false
scala> ("a",3)._2 > ("b",0)._2
res1: Boolean = true
There are several problems in your code which are causing the errors you're seeing.
First, you have a syntax error: to print out the variable highest the way you want to, you need to use + for string concatenation: println("The higher stock is " + highest)
Secondly, highest is only declared inside your if statements so it's out of scope for the println statement. You can solve this issue by declaring it in scope:
...
var highest = 0.0
if(...){
highest = ...
}
else {
highest = ...
}
println("The higher stock is " + highest)
Lastly, and most importantly, the overall design of your method doesn't really make sense to me. f is your parameter to mnuCompareTwoStocks, and it's a function that converts from String to (String, Int). So why are you calling apply (via f(readLine)) on this function and seemingly expecting a numeric datatype back? What is even the purpose of this parameter? If, indeed, you do want the tuple to be returned, you'll need to unpack the numeric component before comparing the values:
val data = f(readLine)
val data2 = f(readLine)
if (data._2 >= data2._2)
...
I see you edited your question to solve the first two issues. However, now you're pointlessly setting val highest = Unit with your if statement...
Regardless, you should unpack the Int component of your tuple if you want to do numeric comparison between them, as shown above.
Related
I have a textfile like so
NameOne,2,3,3
NameTwo,1,0,2
I want to find the indices of the max value in each line in Scala. So the output of this would be
NameOne,1,2
NameTwo,2
I'm currently using the function below to do this but I can't seem to find a simple way to do this without a for loop and I'm wondering if there is a better method out there.
def findIndices(movieRatings: String): (String) = {
val tokens = movieRatings.split(",", -1)
val movie = tokens(0)
val ratings = tokens.slice(1, tokens.size)
val max = ratings.max
var indices = ArrayBuffer[Int]()
for (i<-0 until ratings.length) {
if (ratings(i) == max) {
indices += (i+1)
}
}
return movie + "," + indices.mkString(",")
}
This function is called as so:
val output = textFile.map(findIndices).saveAsTextFile(args(1))
Just starting to learn Scala so any advice would help!
You can zipWithIndex and use filter:
ratings.zipWithIndex
.filter { case(_, value) => value == max }
.map { case(index, _) => index }
I noticed that your code doesn't actually produce the expected result from your example input. I'm going to assume that the example given is the correct result.
def findIndices(movieRatings :String) :String = {
val Array(movie, ratings #_*) = movieRatings.split(",", -1)
val mx = ratings.maxOption //Scala 2.13.x
ratings.indices
.filter(x => mx.contains(ratings(x)))
.mkString(s"$movie,",",","")
}
Note that this doesn't address some of the shortcomings of your algorithm:
No comma allowed in movie name.
Only works for ratings from 0 to 9. No spaces allowed.
testing:
List("AA"
,"BB,"
,"CC,5"
,"DD,2,5"
,"EE,2,5, 9,11,5"
,"a,b,2,7").map(findIndices)
//res0: List[String] = List(AA, <-no ratings
// , BB,0 <-comma, no ratings
// , CC,0 <-one rating
// , DD,1 <-two ratings
// , EE,1,4 <-" 9" and "11" under valued
// , a,0 <-comma in name error
// )
Apologies , but am new to scala... learning it, now.
I have been trying to complete a excercise where the ask was as follows :-
// Write a function isPerfectNumber which takes integer input and returns String output.
// It finds if a number is perfect, and returns true if perfect, else returns false
// Write a higher order function myHigherOrderFunction which takes isPerfectNumber and intList as input, and returns a List of Strings which contain the output if the number is perfect or not using map.
Perfect Number :
https://rosettacode.org/wiki/Perfect_numbers
just go to the scala section
My Code :
object ListMapHigherOrder{
def main(args:Array[String])
{
val intRes = args.toList
val intList: List[Int] = intRes.map(_.toInt).toList
def isPerfectNumber(input: Int) :String =
{
var check_sum = ( (2 to math.sqrt(input).toInt).collect { case x if input % x == 0 => x + input / x} ).sum
if ( check_sum == input - 1 )
return "true"
else
return "false"
}
def myHigherOrderFunction(argFn: Int => String, argVal:List[Int]): List[String] = { argVal.map(argFn) }
println(myHigherOrderFunction(isPerfectNumber, intList))
}
}
Code execution : scala ScalaExcercise12.scala 1 6 13
Expected Output : List(false , true , false)
the code gives expected output, am not sure how the backend testing is being done.... it just dosent pass the test.
Is there any issue with the code? - i did like to fix it , but cant i see anything wrong/missing especially because i am getting the same output as desired :(
object ListMapHigherOrder{
def main(args:Array[String])
{
val intRes = args.toList
val intList: List[Int] = intRes.map(x=>x.toInt)
def isPerfectNumber(input: Int) :String =
{
var sum = 0
for(i <- 1 until input){
if(input % i == 0)
sum = sum+i
}
if ( sum == input )
return "true"
else
return "false"
}
def myHigherOrderFunction(argFn: Int => String, argVal:List[Int]): List[String] = { argVal.map(argFn) }
println(myHigherOrderFunction(isPerfectNumber, intList))
}
}
**This worked for me
In this Scala code I'm trying to analyze a string that contains a sum (such as 12+3+5) and return the result (20). I'm using regex to extract the first digit and parse the trail to be added recursively. My issue is that since the regex returns a String, I cannot add up the numbers. Any ideas?
object TestRecursive extends App {
val plus = """(\w*)\+(\w*)""".r
println(parse("12+3+5"))
def parse(str: String) : String = str match {
// sum
case plus(head, trail) => parse(head) + parse(trail)
case _ => str
}
}
You might want to use the parser combinators for an application like this.
"""(\w*)\+(\w*)""".r also matches "+" or "23+" or "4 +5" // but captures it only in the first group.
what you could do might be
scala> val numbers = "[+-]?\\d+"
numbers: String = [+-]?\d+
^
scala> numbers.r.findAllIn("1+2-3+42").map(_.toInt).reduce(_ + _)
res4: Int = 42
scala> numbers.r.findAllIn("12+3+5").map(_.toInt).reduce(_ + _)
res5: Int = 20
My code is as follows
import scala.collection.mutable.HashMap
type CrossingInterval = (Date, Date)
val crossingMap = new HashMap[String, CrossingInterval]
val crossingData: String = ...
Firstly why does the following line compile?
val time = crossingMap.getOrElse(crossingData, -1)
I would have thought -1 would have been an invalid value
Secondly how do I do a basic check such as the following
if (value exists in map) {
}
else {
}
In Java I would just check for null values. I'm not sure about the proper way to do it in Scala
Typing your code in the interpreter shows why the first statement compiles:
type Date = String
scala> val time = crossingMap.getOrElse(crossingData, -1)
time: Any = -1
Basically, getOrElse on a Map[A, B] (here B = CrossingDate) accepts a parameter of any type B1 >: B: that means that B1 must be a supertype of B. Here B1 = Any, and -1 is of course a valid value of type Any. In this case you actually want to have a type declaration for time.
For testing whether a key belongs to the map, just call the contains method. An example is below - since Date was not available, I simply defined it as an alias to String.
scala> crossingMap.contains(crossingData)
res13: Boolean = false
scala> crossingMap += "" -> ("", "")
res14: crossingMap.type = Map("" -> ("",""))
//Now "" is a map of the key
scala> crossingMap.contains("")
res15: Boolean = true
If you want to check whether a value is part of the map, the simplest way is to write this code:
crossingMap.values.toSet.contains("")
However, this builds a Set containing all values. EDIT: You can find a better solution for this subproblem in Kipton Barros comment.
I was wondering if I can tune the following Scala code :
def removeDuplicates(listOfTuple: List[(Class1,Class2)]): List[(Class1,Class2)] = {
var listNoDuplicates: List[(Class1, Class2)] = Nil
for (outerIndex <- 0 until listOfTuple.size) {
if (outerIndex != listOfTuple.size - 1)
for (innerIndex <- outerIndex + 1 until listOfTuple.size) {
if (listOfTuple(i)._1.flag.equals(listOfTuple(j)._1.flag))
listNoDuplicates = listOfTuple(i) :: listNoDuplicates
}
}
listNoDuplicates
}
Usually if you have someting looking like:
var accumulator: A = new A
for( b <- collection ) {
accumulator = update(accumulator, b)
}
val result = accumulator
can be converted in something like:
val result = collection.foldLeft( new A ){ (acc,b) => update( acc, b ) }
So here we can first use a map to force the unicity of flags. Supposing the flag has a type F:
val result = listOfTuples.foldLeft( Map[F,(ClassA,ClassB)] ){
( map, tuple ) => map + ( tuple._1.flag -> tuple )
}
Then the remaining tuples can be extracted from the map and converted to a list:
val uniqList = map.values.toList
It will keep the last tuple encoutered, if you want to keep the first one, replace foldLeft by foldRight, and invert the argument of the lambda.
Example:
case class ClassA( flag: Int )
case class ClassB( value: Int )
val listOfTuples =
List( (ClassA(1),ClassB(2)), (ClassA(3),ClassB(4)), (ClassA(1),ClassB(-1)) )
val result = listOfTuples.foldRight( Map[Int,(ClassA,ClassB)]() ) {
( tuple, map ) => map + ( tuple._1.flag -> tuple )
}
val uniqList = result.values.toList
//uniqList: List((ClassA(1),ClassB(2)), (ClassA(3),ClassB(4)))
Edit: If you need to retain the order of the initial list, use instead:
val uniqList = listOfTuples.filter( result.values.toSet )
This compiles, but as I can't test it it's hard to say if it does "The Right Thing" (tm):
def removeDuplicates(listOfTuple: List[(Class1,Class2)]): List[(Class1,Class2)] =
(for {outerIndex <- 0 until listOfTuple.size
if outerIndex != listOfTuple.size - 1
innerIndex <- outerIndex + 1 until listOfTuple.size
if listOfTuple(i)._1.flag == listOfTuple(j)._1.flag
} yield listOfTuple(i)).reverse.toList
Note that you can use == instead of equals (use eq if you need reference equality).
BTW: https://codereview.stackexchange.com/ is better suited for this type of question.
Do not use index with lists (like listOfTuple(i)). Index on lists have very lousy performance. So, some ways...
The easiest:
def removeDuplicates(listOfTuple: List[(Class1,Class2)]): List[(Class1,Class2)] =
SortedSet(listOfTuple: _*)(Ordering by (_._1.flag)).toList
This will preserve the last element of the list. If you want it to preserve the first element, pass listOfTuple.reverse instead. Because of the sorting, performance is, at best, O(nlogn). So, here's a faster way, using a mutable HashSet:
def removeDuplicates(listOfTuple: List[(Class1,Class2)]): List[(Class1,Class2)] = {
// Produce a hash map to find the duplicates
import scala.collection.mutable.HashSet
val seen = HashSet[Flag]()
// now fold
listOfTuple.foldLeft(Nil: List[(Class1,Class2)]) {
case (acc, el) =>
val result = if (seen(el._1.flag)) acc else el :: acc
seen += el._1.flag
result
}.reverse
}
One can avoid using a mutable HashSet in two ways:
Make seen a var, so that it can be updated.
Pass the set along with the list being created in the fold. The case then becomes:
case ((seen, acc), el) =>