Since the Math.min() function only allows for the use of 2 elements, I was wondering if there is maybe another function which can calculate the minimum of more than 2 elements.
Thanks in advance!
If you have multiple elements you can just chain calls to the min method:
Math.min(x, Math.min(y, z))
Since scala adds the a min method to numbers via implicits you could write the following which looks much fancier:
x min y min z
If you have a list of values and want to find their minimum:
val someNumbers: List[Int] = ???
val minimum = someNumbers.min
Note that this throws an exception if the list is empty. From scala 2.13.x onwards, there will be a minOption method to handle such cases gracefully. For older versions you could use the reduceOption method as workaround:
someNumbers.reduceOption(_ min _)
someNumbers.reduceOption(Math.min)
Add all numbers in the collection like the list and find a minimum of it.
scala> val list = List(2,3,7,1,9,4,5)
list: List[Int] = List(2, 3, 7, 1, 9, 4, 5)
scala> list.min
res0: Int = 1
Related
I'm completely new to Scala so bear with me please! I am going through some Scala exercises and one of them is to create a list of odd numbers from 1 to 20. This is pretty straight forward but I'm a bit confused about the return type of the filter method on a range.
I have the following block:
val lst2 = (1 to 20).filter(_ % 2 != 0)
println(lst2)
The output of this is:
Vector(1, 3, 5, 7, 9, 11, 13, 15, 17, 19)
However when I explicitly set the type of lst2 to Vector[Int] like the following:
val lst2: Vector[Int] = (1 to 20).filter(_ % 2 != 0)
println(lst2)
I get the this:
16: error: type mismatch;
found : scala.collection.immutable.IndexedSeq[Int]
required: Vector[Int]
val lst2: Vector[Int] = (1 to 20).filter(_ % 2 != 0)
^
one error found
So what's gonig on here? Is the println method just not giving me the correct type? How do I get the filter method to return a Vector?
The only guarantee that is provided by filter of Range is that it returns a collection.immutable.IndexedSeq[A], so this compiles:
val lst2: collection.immutable.IndexedSeq[Int] = (1 to 20).filter(_ % 2 == 1)
At runtime, lst2 just happens to be a Vector[Int], but this is not guaranteed by the interface, so the authors of the filter method effectively reserve the right to change the concrete implementation to another IndexedSeq whenever they like. The type Vector is an implementation detail you shouldn't rely on.
The reason why it's printed as Vector(...) is that it depends on the implementation of toString of a concrete instance that is present at runtime, not on the statically know type (dynamic dispatch).
If you really want something with type Vector, just append .toVector:
val lst2: Vector[Int] = (0 to 20).filter(_ % 2 == 1).toVector
Here is a function which makes a map from given array. Where key is the integer number and the value is the frequency of this number in the given array.
I need to find the key which has the maximum frequency. If two key has the same frequency then i need to take the key which is smaller.
that's what i have written:
def findMinKeyWithMaxFrequency(arr: List[Int]): Int = {
val ansMap:scala.collection.mutable.Map[Int,Int] = scala.collection.mutable.Map()
arr.map(elem=> ansMap+=(elem->arr.count(p=>elem==p)))
ansMap.filter(_._2==ansMap.values.max).keys.min
}
val arr = List(1, 2 ,3, 4, 5, 4, 3, 2, 1, 3, 4)
val ans=findMinKeyWithMaxFrequency(arr) // output:3
How can i make it more efficient, it is giving me the right answer but i don't think it's the most efficient way to solve the problem.
In the given example the frequency of 3 and 4 is 3 so the answer should be 3 as 3 is smaller than 4.
Edit 1:
That's what i have done to make it bit efficient. Which is converting arr into Set as we need to find frequency for the unique elements only.
def findMinKeyWithMaxFrequency(arr: List[Int]): Int = {
val ansMap=arr.toSet.map{ e: Int =>(e,arr.count(x=>x==e))}.toMap
ansMap.filter(_._2==ansMap.values.max).keys.min
}
Can it be more efficient? Is it the most functional way of writing the solution for the given problem.
def findMinKeyWithMaxFrequency(arr: List[Int]): Int =
arr.groupBy(identity).toSeq.maxBy(p => (p._2.length,-p._1))._1
Use groupBy() to get an effective count for each element then, after flattening to a sequence of tuples, code the required rules to determine the maximum.
For example, my input is:
scala> val myList = List("7842", "abf45", "abd", "56")
myList: List[String] = List(7842, abf45, abd, 56)
7842 and 56 can be converted to Int; therefore, my expected output is 2. We can assume that negative integers don't happen, so -67 is not possible.
This is what I have so far:
scala> myList.map(x => Try(x.toInt).getOrElse(-1)).count(_ > -1)
res15: Int = 2
This should work correctly, but I feel like I am missing a more elegant and readable solution, because all I have to do is count number of successes.
I would caution against using exception handling (like Try) in control flow -- it's very slow.
Here's a solution that uses idiomatic Scala collection operations, performs well, and will not count negative numbers:
scala> val myList = List("7842", "abf45", "abd", "56")
myList: List[String] = List(7842, abf45, abd, 56)
scala> myList.count(_.forall(_.isDigit))
res8: Int = 2
EDIT: #immibis pointed out that this won't detect strings of numbers that exceed Integer.MaxValue. If this is a concern, I would recommend one of the following approaches:
import scala.util.Try
myList.count(x => Try(x.toInt).filter(_ >= 0).isSuccess)
or, if you want to keep the performance of my first answer while still handling this edge case:
import scala.util.Try
myList.count(x => x.forall(_.isDigit) && Try(x.toInt).filter(_ >= 0).isSuccess)
This is a bit shorter:
myList.count(x => Try(x.toInt).isSuccess)
Note that this solution will handle any string that can be converted to integer via .toInt, including negative numbers.
You may consider string.matches method with regex as well, to match only positive integers:
val myList = List("7842", "abf45", "abd", "-56")
// myList: List[String] = List(7842, abf45, abd, -56)
myList.count(_.matches("\\d+"))
// res18: Int = 1
If negative integers need to be counted (and take into account possible +/- signs):
myList.count(_.matches("[+-]?\\d+"))
// res17: Int = 2
Starting Scala 2.13 and the introduction of String::toIntOption, we can count items ("34"/"2s3") for which applying toIntOption (Some(34)/None) is defined (true/false):
List("34", "abf45", "2s3", "56").count(_.toIntOption.isDefined) // 2
I am new to Scala and I am still trying to get used to its syntax and rules.
I have a method that takes two inputs and returns a list with the numbers in between, excluding the last number. For example:
int a = 2
int b = 5
The list would be {2,3,4}
I have a method that creates a list but also account for the last digit.
def fromTo(low:Int,high:Int): List[Int] = {
if(low == high)
lo::Nil
else
lo::fromTo(low+1,hi)
}
I tried creating a new variable but that did not work. Any ideas on how to make that last digit not be part of the list?
Think about your base case. What happens if you call fromTo(a,a) for some integer a.
Maybe a bit off topic, but you're also assuming that low <= high might want to look into that as well.
I'm not sure if you are specifically trying to do this with a recursive call but if all you really want is the list of numbers from X to Y excluding Y, you can just do the following:
scala> (2 until 5).toList
res3: List[Int] = List(2, 3, 4)
I'm looking for an elegant way to get a slice of a list from element n onwards without having to specify the length of the list. Lets say we have a multiline string which I split into lines and then want to get a list of all lines from line 3 onwards:
string.split("\n").slice(3,X) // But I don't know what X is...
What I'm really interested in here is whether there's a way to get hold of a reference of the list returned by the split call so that its length can be substituted into X at the time of the slice call, kind of like a fancy _ (in which case it would read as slice(3,_.length)) ? In python one doesn't need to specify the last element of the slice.
Of course I could solve this by using a temp variable after the split, or creating a helper function with a nice syntax, but I'm just curious.
Just drop first n elements you don't need:
List(1,2,3,4).drop(2)
res0: List[Int] = List(3, 4)
or in your case:
string.split("\n").drop(2)
There is also paired method .take(n) that do the opposite thing, you can think of it as .slice(0,n).
In case you need both parts, use .splitAt:
val (left, right) = List(1,2,3,4).splitAt(2)
left: List[Int] = List(1, 2)
right: List[Int] = List(3, 4)
The right answer is takeRight(n):
"communism is sharing => resource saver".takeRight(3)
//> res0: String = ver
You can use scala's list method 'takeRight',This will not throw exception when List's length is not enough, Like this:
val t = List(1,2,3,4,5);
t.takeRight(3);
res1: List[Int] = List(3,4,5)
If list is not longer than you want take, this will not throw Exception:
val t = List(4,5);
t.takeRight(3);
res1: List[Int] = List(4,5)
get last 2 elements:
List(1,2,3,4,5).reverseIterator.take(2)