passing variable argument data type to a scala method - scala

I want to create a method/function in scala which can take variable arguments of type string or int and return the result of type String or Int.
def Hello(name: String, Param: int*/string*): Int/String= {
var index = 0
while(index < Param.length) {
var n = name
var ar = Param(index)
if ( n.equals(ar) ) return Param(index + 1)
else index = index + 1
}
return Param(index.length -1)
}
If we call the Hello function then it should return the result as given below.
val Res1 = Hello("Jack", "rakesh", 1, "Jack", 2, "No one")
println(Res1)
=> this should return value 2
val Res2 = Hello("ABC", "rakesh", 1, "Jack", 2, "Vik", 3, "ram", 4, "No one")
println(Res2)
=> this should return value "No one"

Using Any should work:
def hello(name: Any, param: Any*): Any= {
var list = param.dropWhile(_ != name)
list.drop(1).headOption.orElse(param.lastOption).getOrElse("")
}
Depending on how type safe you want it to be, you can try to use generics or other means to restrict the types used. Or you can just pattern match the response type:
hello("ABC", "rakesh", 1, "Jack", 2, "Vik", 3, "ram", 4, "No one") match {
case i: Int => println("Got a int:" + i)
case s: String=> println("Got a string:" + s)
}

This will help you
def Hello( name: String,args: Any* ) = {
val index = args.indexOf(name)
if(index == -1)
args(args.length - 1)
else
args(index + 1)
}

Your whole approach is faulty, but here's how it can be done in a type-safe manner.
def Hello(name: String, param: Either[Int,String]*): Either[Int,String] = {
param.sliding(2,2)
.find(_(0).fold(_ => false, _ == name))
.fold(param.last)(_(1))
}
Usage:
Hello("Jack", Right("rakesh"), Left(1), Right("Jack"), Left(2), Right("No one"))
// res0: Either[Int,String] = Left(2)
Hello("ABC", Right("rakesh"), Left(1), Right("Jack"), Left(2),
Right("Vik"), Left(3), Right("ram"), Left(4), Right("No one"))
// res1: Either[Int,String] = Right(No one)
But it would be better to rethink it from the ground up.

I believe, what you want to achieve, is to get an index of a String element(if start counting from 1) in varargs, or return "No one". No need to pass indices to the method. You can do it like this:
def hello(name: String, params: String*): Any = {
val idx = params.indexOf(name)
if (idx != -1) idx + 1 else "No One"
}
Unfortunately both this:
def Hello(name: String, args: Any* ) = {
val index = args.indexOf(name)
if(index == -1)
args(args.length - 1)
else
args(index + 1)
}
and this:
def hello(name: String, param: Any*): Any= {
var index = 0
while(index < param.length) {
var n = name
var ar = param(index)
if ( n.equals(ar) ) return param(index + 1)
else index = index + 1
}
param(index -1)
}
are broken, as they throw an exception if you try to find the index of "No one", as index + 1 will equal to the size of the array. And it's better to compare things in Scala with == for logical equality.
But it's better not to return Any at all, but return Option[Int]:
def hello(name: String, params: String*): Option[Int] =
Option(params.indexOf(name)).filter(_ != -1).map(_ + 1)
So then you can use it like this:
val message1 = hello("Jack", "rakesh" ,"Jack").getOrElse("No one")
val message2 = hello("ABC", "rakesh", "Jack", "Vik", "ram").getOrElse("No one")
Answering the comment:
I want to know how can i pass mixed datatypes to "param".
The simplest way is to have them all of type Any
and also get string or integer as return type
The same way, defining return type as Any
The only small issue here, is that there will be no compile time check against other types. E.g. somebody might pass Boolean or any complex object along with String's and Int's to your function. But you can check at runtime against it or play with types to limit them. I don't know your requirement here, maybe it's even advantage for you.
If having Any is fine, then I would solve it like this:
def Hello(name: Any, params: Any*): Any = Option(params)
.withFilter(_.nonEmpty)
.map(_.indexOf(name))
.filter(i => i != -1 && i < params.length - 1)
.map(i => params(i + 1))
.getOrElse("No one")
Or, if you can assume, params are never empty and you have to use the last param as the default, instead of just hard coded "No one":
def Hello(name: Any, params: Any*): Any = Option(params)
.withFilter(_.nonEmpty)
.map(_.indexOf(name))
.filter(i => i != -1 && i < params.length - 1)
.map(i => params(i + 1))
.getOrElse(params.last)
Notice the check against "No one" attack: i < params.length - 1.
Notice that name now is also of type Any.
Now, even if you pass "No one" as a name, the Option will evaluate to None thanking to the filter, and getOrElse will give you the default "No one" instead of an exception.

Related

Validation that returns more than 1 error

I'm doing a few validations using an older Scala version (2.0) but for each record I am currently getting only 1 error, assuming the record has 2 or more error -- I want to receive everything wrong with that record/item
case class Response(request: JsValue,
success: Boolean,
column: Option[String] = None,
message: String = "")
Here is validator, that return all errors in a json object
def validator(asJson: JsValue): Response = {
if (name == "")
return Response(asJson, false, Some("name"), "Name can't be blank")
if (age == -1 || age == "N/A")
return Response(asJson, false, Some("age"), "Age can't be blank")
if (DOB == -1 || DOB == "N/A" )
return Response(asJson, false, Some("DOB"), "DOB cannot be blank")
else
Response(asJson, true)
}
Currently if record1 doesn't have a name + age + DOB ---> I'm only getting "Name can't be blank"
How do I get (multiple errors per item instead of just 1 error per item):
Name can't be blank, Age can't be blank, DOB cannot be blank
This is just an outline of how it might work:
def validator(asJson: JsValue): Response = {
val errors = List(
if (name == "" ) Some("Name can't be blank") else None,
if (age == -1 || age == "N/A") Some("Age can't be blank") else None,
if (DOB == -1 || DOB == "N/A" ) Some("DOB cannot be blank") else None,
).flatten
if (errors.isEmpty) {
Response(asJson, true)
} else {
Response(asJson, false, errors.mkString(", "))
}
}
The errors value is created by making a List of Option values, one for each validation check. The flatten method extracts the contents of all the Some values and removes any None values. The result is a list of error strings.
The rest of the code formats the Response based on the list of errors.
If you are using Scala 2.13 then Option.when makes the tests shorter and clearer:
Option.when(name == "")("Name can't be blank"),
Option.when(age == -1 || age == "N/A")("Age can't be blank"),
Option.when(DOB == -1 || DOB == "N/A")("DOB cannot be blank"),
Here is an alternative using Validated that you might consider at some point
import play.api.libs.json._
import cats.data.ValidatedNec
import cats.implicits._
case class User(name: String, age: Int, dob: String)
case class UserDTO(name: Option[String], age: Option[Int], dob: Option[String])
implicit val userDtoFormat = Json.format[UserDTO]
val raw =
"""
|{
| "name": "Picard"
|}
|""".stripMargin
val userDto = Json.parse(raw).as[UserDTO]
def validateUser(userDto: UserDTO): ValidatedNec[String, User] = {
def validateName(user: UserDTO): ValidatedNec[String, String] =
user.name.map(_.validNec).getOrElse("Name is empty".invalidNec)
def validateAge(user: UserDTO): ValidatedNec[String, Int] =
user.age.map(_.validNec).getOrElse("Age is empty".invalidNec)
def validateDob(user: UserDTO): ValidatedNec[String, String] =
user.dob.map(_.validNec).getOrElse("DOB is empty".invalidNec)
(validateName(userDto), validateAge(userDto), validateDob(userDto)).mapN(User)
}
validateUser(userDto)
// res0: cats.data.ValidatedNec[String,User] = Invalid(Chain(Age is empty, DOB is empty))
Note the distinction between UserDTO ("data transfer object") which models whatever payload was sent over the wire, and User which models the actual data we require for our business logic. We separate the concern of user validation into its own method validateUser. Now we can work with valid user or errors like so
validateUserDTO(userDto) match {
case Valid(user) =>
// do something with valid user
case Invalid(errors) =>
// do something with errors
}
First of all, in scala you do not have the return statement, the last statement is returned (in fact it exists but its use is not recomended).
Secondly, in your code, I suppose you want to pass through several if statements. But if you return after each if statement you exit your function at the first condition that is true, and you will never go to the rest of the code.
If you want to gather several instances of Response, just gather them in a collection, and return the collection at the end of the function. A collection might be a List, or a Seq, or whatever.
In my code I've simple Validator that does exactly that:
abstract class Validator[T, ERR >: Null] {
def validate(a:T):Seq[ERR]
protected def is(errorCase:Boolean, err: => ERR) = if (errorCase) err else null
protected def check(checks:ERR*) = checks.collectFirst{ case x if x != null => x }.getOrElse(null)
protected def checkAll(checks:ERR*) = checks.filter(_ != null)
}
//implement checks on some types
val passwordValidator = new Validator[String, String] {
val universalPasswordInstruction = "Password needs to have at least one small letter, big letter, number and other sign."
def validate(a: String) = checkAll( //here we check all cases
is(a.length < 10, "Password should be longer than 10"),
check( //here we check only first one.
is(a.forall(_.isLetter), s"Passowrd has only letters. $universalPasswordInstruction"),
is(a.forall(_.isLetterOrDigit), s"Use at least one ascii character like '#' or '*'. $universalPasswordInstruction"),
),
is(a.contains("poop"), "Really!")
)
}
val userValidator = new Validator[(String, String), (Int, String)] {
override def validate(a: (String, String)): Seq[(Int, String)] = checkAll(
is(a._1.length > 0, (0, "Username is empty!")),
) ++ passwordValidator.validate(a._2).map(x => (1, x))
}
//use
userValidator.validate("SomeUserName" -> "SomePassword") match {
case Seq() => //OK case
case errors => //deal with it
}
Maybe not so fancy but works for me :). Code is simple and rather self explanatory. Nulls here are just implementation detail (they doesn't show up in usercode, and can be switched to Options).

Scala String Equality Question from Programming Interview

Since I liked programming in Scala, for my Google interview, I asked them to give me a Scala / functional programming style question. The Scala functional style question that I got was as follows:
You have two strings consisting of alphabetic characters as well as a special character representing the backspace symbol. Let's call this backspace character '/'. When you get to the keyboard, you type this sequence of characters, including the backspace/delete character. The solution you are to implement must check if the two sequences of characters produce the same output. For example, "abc", "aa/bc". "abb/c", "abcc/", "/abc", and "//abc" all produce the same output, "abc". Because this is a Scala / functional programming question, you must implement your solution in idiomatic Scala style.
I wrote the following code (it might not be exactly what I wrote, I'm just going off memory). Basically I just go linearly through the string, prepending characters to a list, and then I compare the lists.
def processString(string: String): List[Char] = {
string.foldLeft(List[Char]()){ case(accumulator: List[Char], char: Char) =>
accumulator match {
case head :: tail => if(char != '/') { char :: head :: tail } else { tail }
case emptyList => if(char != '/') { char :: emptyList } else { emptyList }
}
}
}
def solution(string1: String, string2: String): Boolean = {
processString(string1) == processString(string2)
}
So far so good? He then asked for the time complexity and I responded linear time (because you have to process each character once) and linear space (because you have to copy each element into a list). Then he asked me to do it in linear time, but with constant space. I couldn't think of a way to do it that was purely functional. He said to try using a function in the Scala collections library like "zip" or "map" (I explicitly remember him saying the word "zip").
Here's the thing. I think that it's physically impossible to do it in constant space without having any mutable state or side effects. Like I think that he messed up the question. What do you think?
Can you solve it in linear time, but with constant space?
This code takes O(N) time and needs only three integers of extra space:
def solution(a: String, b: String): Boolean = {
def findNext(str: String, pos: Int): Int = {
#annotation.tailrec
def rec(pos: Int, backspaces: Int): Int = {
if (pos == 0) -1
else {
val c = str(pos - 1)
if (c == '/') rec(pos - 1, backspaces + 1)
else if (backspaces > 0) rec(pos - 1, backspaces - 1)
else pos - 1
}
}
rec(pos, 0)
}
#annotation.tailrec
def rec(aPos: Int, bPos: Int): Boolean = {
val ap = findNext(a, aPos)
val bp = findNext(b, bPos)
(ap < 0 && bp < 0) ||
(ap >= 0 && bp >= 0 && (a(ap) == b(bp)) && rec(ap, bp))
}
rec(a.size, b.size)
}
The problem can be solved in linear time with constant extra space: if you scan from right to left, then you can be sure that the /-symbols to the left of the current position cannot influence the already processed symbols (to the right of the current position) in any way, so there is no need to store them.
At every point, you need to know only two things:
Where are you in the string?
How many symbols do you have to throw away because of the backspaces
That makes two integers for storing the positions, and one additional integer for temporary storing the number of accumulated backspaces during the findNext invocation. That's a total of three integers of space overhead.
Intuition
Here is my attempt to formulate why the right-to-left scan gives you a O(1) algorithm:
The future cannot influence the past, therefore there is no need to remember the future.
The "natural time" in this problem flows from left to right. Therefore, if you scan from right to left, you are moving "from the future into the past", and therefore you don't need to remember the characters to the right of your current position.
Tests
Here is a randomized test, which makes me pretty sure that the solution is actually correct:
val rng = new util.Random(0)
def insertBackspaces(s: String): String = {
val n = s.size
val insPos = rng.nextInt(n)
val (pref, suff) = s.splitAt(insPos)
val c = ('a' + rng.nextInt(26)).toChar
pref + c + "/" + suff
}
def prependBackspaces(s: String): String = {
"/" * rng.nextInt(4) + s
}
def addBackspaces(s: String): String = {
var res = s
for (i <- 0 until 8)
res = insertBackspaces(res)
prependBackspaces(res)
}
for (i <- 1 until 1000) {
val s = "hello, world"
val t = "another string"
val s1 = addBackspaces(s)
val s2 = addBackspaces(s)
val t1 = addBackspaces(t)
val t2 = addBackspaces(t)
assert(solution(s1, s2))
assert(solution(t1, t2))
assert(!solution(s1, t1))
assert(!solution(s1, t2))
assert(!solution(s2, t1))
assert(!solution(s2, t2))
if (i % 100 == 0) {
println(s"Examples:\n$s1\n$s2\n$t1\n$t2")
}
}
A few examples that the test generates:
Examples:
/helly/t/oj/m/, wd/oi/g/x/rld
///e/helx/lc/rg//f/o, wosq//rld
/anotl/p/hhm//ere/t/ strih/nc/g
anotx/hb/er sw/p/tw/l/rip/j/ng
Examples:
//o/a/hellom/, i/wh/oe/q/b/rld
///hpj//est//ldb//y/lok/, world
///q/gd/h//anothi/k/eq/rk/ string
///ac/notherli// stri/ig//ina/n/g
Examples:
//hnn//ello, t/wl/oxnh///o/rld
//helfo//u/le/o, wna//ova//rld
//anolq/l//twl//her n/strinhx//g
/anol/tj/hq/er swi//trrq//d/ing
Examples:
//hy/epe//lx/lo, wr/v/t/orlc/d
f/hk/elv/jj//lz/o,wr// world
/anoto/ho/mfh///eg/r strinbm//g
///ap/b/notk/l/her sm/tq/w/rio/ng
Examples:
///hsm/y//eu/llof/n/, worlq/j/d
///gx//helf/i/lo, wt/g/orn/lq/d
///az/e/notm/hkh//er sm/tb/rio/ng
//b/aen//nother v/sthg/m//riv/ng
Seems to work just fine. So, I'd say that the Google-guy did not mess up, looks like a perfectly valid question.
You don't have to create the output to find the answer. You can iterate the two sequences at the same time and stop on the first difference. If you find no difference and both sequences terminate at the same time, they're equal, otherwise they're different.
But now consider sequences such as this one: aaaa/// to compare with a. You need to consume 6 elements from the left sequence and one element from the right sequence before you can assert that they're equal. That means that you would need to keep at least 5 elements in memory until you can verify that they're all deleted. But what if you iterated elements from the end? You would then just need to count the number of backspaces and then just ignoring as many elements as necessary in the left sequence without requiring to keep them in memory since you know they won't be present in the final output. You can achieve O(1) memory using these two tips.
I tried it and it seems to work:
def areEqual(s1: String, s2: String) = {
def charAt(s: String, index: Int) = if (index < 0) '#' else s(index)
#tailrec
def recSol(i1: Int, backspaces1: Int, i2: Int, backspaces2: Int): Boolean = (charAt(s1, i1), charAt(s2, i2)) match {
case ('/', _) => recSol(i1 - 1, backspaces1 + 1, i2, backspaces2)
case (_, '/') => recSol(i1, backspaces1, i2 - 1, backspaces2 + 1)
case ('#' , '#') => true
case (ch1, ch2) =>
if (backspaces1 > 0) recSol(i1 - 1, backspaces1 - 1, i2 , backspaces2 )
else if (backspaces2 > 0) recSol(i1 , backspaces1 , i2 - 1, backspaces2 - 1)
else ch1 == ch2 && recSol(i1 - 1, backspaces1 , i2 - 1, backspaces2 )
}
recSol(s1.length - 1, 0, s2.length - 1, 0)
}
Some tests (all pass, let me know if you have more edge cases in mind):
// examples from the question
val inputs = Array("abc", "aa/bc", "abb/c", "abcc/", "/abc", "//abc")
for (i <- 0 until inputs.length; j <- 0 until inputs.length) {
assert(areEqual(inputs(i), inputs(j)))
}
// more deletions than required
assert(areEqual("a///////b/c/d/e/b/b", "b"))
assert(areEqual("aa/a/a//a//a///b", "b"))
assert(areEqual("a/aa///a/b", "b"))
// not enough deletions
assert(!areEqual("aa/a/a//a//ab", "b"))
// too many deletions
assert(!areEqual("a", "a/"))
PS: just a few notes on the code itself:
Scala type inference is good enough so that you can drop types in the partial function inside your foldLeft
Nil is the idiomatic way to refer to the empty list case
Bonus:
I had something like Tim's soltion in mind before implementing my idea, but I started early with pattern matching on characters only and it didn't fit well because some cases require the number of backspaces. In the end, I think a neater way to write it is a mix of pattern matching and if conditions. Below is my longer original solution, the one I gave above was refactored laater:
def areEqual(s1: String, s2: String) = {
#tailrec
def recSol(c1: Cursor, c2: Cursor): Boolean = (c1.char, c2.char) match {
case ('/', '/') => recSol(c1.next, c2.next)
case ('/' , _) => recSol(c1.next, c2 )
case (_ , '/') => recSol(c1 , c2.next)
case ('#' , '#') => true
case (a , b) if (a == b) => recSol(c1.next, c2.next)
case _ => false
}
recSol(Cursor(s1, s1.length - 1), Cursor(s2, s2.length - 1))
}
private case class Cursor(s: String, index: Int) {
val char = if (index < 0) '#' else s(index)
def next = {
#tailrec
def recSol(index: Int, backspaces: Int): Cursor = {
if (index < 0 ) Cursor(s, index)
else if (s(index) == '/') recSol(index - 1, backspaces + 1)
else if (backspaces > 1) recSol(index - 1, backspaces - 1)
else Cursor(s, index - 1)
}
recSol(index, 0)
}
}
If the goal is minimal memory footprint, it's hard to argue against iterators.
def areSame(a :String, b :String) :Boolean = {
def getNext(ci :Iterator[Char], ignore :Int = 0) : Option[Char] =
if (ci.hasNext) {
val c = ci.next()
if (c == '/') getNext(ci, ignore+1)
else if (ignore > 0) getNext(ci, ignore-1)
else Some(c)
} else None
val ari = a.reverseIterator
val bri = b.reverseIterator
1 to a.length.max(b.length) forall(_ => getNext(ari) == getNext(bri))
}
On the other hand, when arguing FP principals it's hard to defend iterators, since they're all about maintaining state.
Here is a version with a single recursive function and no additional classes or libraries. This is linear time and constant memory.
def compare(a: String, b: String): Boolean = {
#tailrec
def loop(aIndex: Int, aDeletes: Int, bIndex: Int, bDeletes: Int): Boolean = {
val aVal = if (aIndex < 0) None else Some(a(aIndex))
val bVal = if (bIndex < 0) None else Some(b(bIndex))
if (aVal.contains('/')) {
loop(aIndex - 1, aDeletes + 1, bIndex, bDeletes)
} else if (aDeletes > 0) {
loop(aIndex - 1, aDeletes - 1, bIndex, bDeletes)
} else if (bVal.contains('/')) {
loop(aIndex, 0, bIndex - 1, bDeletes + 1)
} else if (bDeletes > 0) {
loop(aIndex, 0, bIndex - 1, bDeletes - 1)
} else {
aVal == bVal && (aVal.isEmpty || loop(aIndex - 1, 0, bIndex - 1, 0))
}
}
loop(a.length - 1, 0, b.length - 1, 0)
}

Scala Do While Loop Not Ending

I'm new to scala and i'm trying to implement a do while loop but I cannot seem to get it to stop. Im not sure what i'm doing wrong. If someone could help me out that would be great. Its not the best loop I know that but I am new to the language.
Here is my code below:
def mnuQuestionLast(f: (String) => (String, Int)) ={
var dataInput = true
do {
print("Enter 1 to Add Another 0 to Exit > ")
var dataInput1 = f(readLine)
if (dataInput1 == 0){
dataInput == false
} else {
println{"Do the work"}
}
} while(dataInput == true)
}
You're comparing a tuple type (Tuple2[String, Int] in this case) to 0, which works because == is defined on AnyRef, but doesn't make much sense when you think about it. You should be looking at the second element of the tuple:
if (dataInput1._2 == 0)
Or if you want to enhance readability a bit, you can deconstruct the tuple:
val (line, num) = f(readLine)
if (num == 0)
Also, you're comparing dataInput with false (dataInput == false) instead of assigning false:
dataInput = false
Your code did not pass the functional conventions.
The value that the f returns is a tuple and you should check it's second value of your tuple by dataInput1._2==0
so you should change your if to if(dataInput1._2==0)
You can reconstruct your code in a better way:
import util.control.Breaks._
def mnuQuestionLast(f: (String) => (String, Int)) = {
breakable {
while (true) {
print("Enter 1 to Add Another 0 to Exit > ")
f(readLine) match {
case (_, 0) => break()
case (_,1) => println( the work"
case _ => throw new IllegalArgumentException
}
}
}
}

is it possible to write functional version for below imperative code in scala

I wrote sum code in scala to find the majority element(the element which appears more than n/2 times where 'n' is the no.of elements in an array.I want to know where there is functional / scala native style of version(which includes match cases and transformations like "map/"flatmap" etc..) for the below imperative style of scala code which includes looping. The code which i used in:
object MajorityElement{
def printMajority(arr:Array[Int]) ={
var cand:Int=findCandidate(arr);
if(isMajority(arr,cand))
println(cand);
else
println("No Majority Element");
}
def isMajority(arr:Array[Int],Cand:Int):Boolean ={
var count=0;
for(i <- 0 until arr.length){
if(arr(i)== Cand)
count+=1;
}
if (count > arr.size/2)
return true;
else false
}
def findCandidate(arr:Array[Int]):Int ={
val s = arr.size
var majIndex:Int = 0;
var count = 1;
for(i <- 0 until arr.length){
if(arr(majIndex) == arr(i))
count+=1;
else
count-=1;
if(count==0)
{
majIndex = i;
count =1
}
}
return arr(majIndex);
}
}
please let me know, whether it is possible to write/ convert imperative style to functional version in scala(which uses match cases) for any scenario.
If you're only interested in the final result (and so you don't need isMajority etc), it's very simple
def findMajority(xs: List[Int]) = {
val mostFrequent = xs.groupBy(identity).values.maxBy(_.length)
if (mostFrequent.length >= xs.length / 2) Some(mostFrequent.head) else None
}
findMajority(List(1, 2, 2, 2, 3, 3, 3, 3, 3, 4))
//Option[Int] = Some(3)
Group equal elements into lists (the values of the Map returned by GroupBy). Pick the longest list. If its length is more than half the list, then it's a majority, return Some(the head) (any element will do, they're all the same value). Otherwise, return None
The transition from imperative thinking to functional thinking takes time and study. One approach is to find code examples here on SO and, with the help of the Standard Library, break it down until you understand what's going on.
Here's a little something to get you started.
def isMajority(arr:Array[Int],cand:Int):Boolean =
arr.count(_ == cand) > arr.size/2
Threr is no Native Scala Style, but code can be Functional Style(value oriented)
(No var, No Side-Effect, Pure Function)
object MajorityElement {
case class Candidate(idx: Int, count: Int)
def solve(arr: Array[Int]): Option[Int] = {
val candidate = findCandidate(arr)
if (isMajority(arr, candidate)) Option(arr(candidate.idx))
else None
}
def isMajority(arr: Array[Int], candidate: Candidate) =
arr.count(_ == arr(candidate.idx)) > arr.size / 2
def findCandidate(arr: Array[Int]): Candidate =
arr.indices.foldLeft(Candidate(0, 1)) { (acc, idx) =>
val newAcc =
if (arr(acc.idx) == arr(idx)) acc.copy(count = acc.count + 1)
else acc.copy(count = acc.count - 1)
if (newAcc.count == 0) Candidate(idx, 1)
else newAcc
}
}
val arr = Array(1, 1, 1, 2, 3, 4, 1)
val ret = MajorityElement.solve(arr)
ret match {
case Some(n) => println(s"Found Majority Element: $n")
case None => println("No Majority Element")
}

Multiple if else statements to get non-empty value from a map in Scala

I have a string to string map, and its value can be an empty string. I want to assign a non-empty value to a variable to use it somewhere. Is there a better way to write this in Scala?
import scala.collection.mutable
var keyvalue = mutable.Map.empty[String, String]
keyvalue += ("key1" -> "value1")
var myvalue = ""
if (keyvalue.get("key1").isDefined &&
keyvalue("key1").length > 0) {
myvalue = keyvalue("key1")
}
else if (keyvalue.get("key2").isDefined &&
keyvalue("key2").length > 0) {
myvalue = keyvalue("key2")
}
else if (keyvalue.get("key3").isDefined &&
keyvalue("key3").length > 0) {
myvalue = keyvalue("key3")
}
A more idiomatic way would be to use filter to check the length of the string contained in the Option, then orElse and getOrElse to assign to a val. A crude example:
def getKey(key: String): Option[String] = keyvalue.get(key).filter(_.length > 0)
val myvalue: String = getKey("key1")
.orElse(getKey("key2"))
.orElse(getKey("key3"))
.getOrElse("")
Here's a similar way to do it with an arbitrary list of fallback keys. Using a view and collectFirst, we will only evaluate keyvalue.get for only as many times as we need to (or all, if there are no matches).
val myvalue: String = List("key1", "key2", "key3").view
.map(keyvalue.get)
.collectFirst { case Some(value) if(value.length > 0) => value }
.getOrElse("")
Mmm, it seems it took me too long to devise a generic solution and other answer was accepted, but here it goes:
def getOrTryAgain(map: mutable.Map[String, String], keys: List[String]): Option[String] =
{
if(keys.isEmpty)
None
else
map.get(keys.head).filter(_.length > 0).orElse(getOrTryAgain(map, keys.tail))
}
val myvalue2 = getOrTryAgain(keyvalue, List("key1", "key2", "key3"))
This one you can use to check for as many keys as you want.