I want to get first argument for main method that is optional, something like this:
val all = args(0) == "all"
However, this would fail with exception if no argument is provided.
Is there any one-liner simple method to set all to false when args[0] is missing; and not doing the common if-no-args-set-false-else... thingy?
In general case you can use lifting:
args.lift(0).map(_ == "all").getOrElse(false)
Or even (thanks to #enzyme):
args.lift(0).contains("all")
You can use headOption and fold (on Option):
val all = args.headOption.fold(false)(_ == "all")
Of course, as #mohit pointed out, map followed by getOrElse will work as well.
If you really need indexed access, you could pimp a get method on any Seq:
implicit class RichIndexedSeq[V, T <% Seq[V]](seq: T) {
def get(i: Int): Option[V] =
if (i < 0 || i >= seq.length) None
else Some(seq(i))
}
However, if this is really about arguments, you'll be probably better off, handling arguments in a fold:
case class MyArgs(n: Int = 1, debug: Boolean = false,
file: Option[String] = None)
val myArgs = args.foldLeft(MyArgs()) {
case (args, "-debug") =>
args.copy(debug = true)
case (args, str) if str.startsWith("-n") =>
args.copy(n = ???) // parse string
case (args, str) if str.startsWith("-f") =>
args.copy(file = Some(???) // parse string
case _ =>
sys.error("Unknown arg")
}
if (myArgs.file.isEmpty)
sys.error("Need file")
You can use foldLeft with initial false value:
val all = (false /: args)(_ | _ == "all")
But be careful, One Liners can be difficult to read.
Something like this will work assuming args(0) returns Some or None:
val all = args(0).map(_ == "all").getOrElse(false)
Related
i'm getting an error when trying to getOrElse 2 values. As a stripped down example, all i'm trying to do is:
take a string value
check if its a range (eg 50-60). if it is, take the first value before the '-', else take the whole value
return the value as an Option[Double] for further processing
def deriveResult(inputValue: Option[String]): String = {
val hyphenIndex = inputValue.get.indexOf("-")
// parse the low range
val rangedValue: Option[java.lang.Double] = if (hyphenIndex != -1) {
val lowRangeStringUntruncated = inputValue.get.substring (0, hyphenIndex)
val lowRangeString = lowRangeStringUntruncated.substring (0, scala.math.min (lowRangeStringUntruncated.length, 8) )
scala.util.Try[java.lang.Double](lowRangeString.toDouble).toOption
} else null
val nonRangedValue: Option[java.lang.Double] = scala.util.Try[java.lang.Double](inputValue.get.toDouble).toOption
val valueOptDouble: Option[java.lang.Double] = Option(rangedValue.getOrElse(nonRangedValue))
...
<do something with valueOptDouble>
}
Error:(157, 89) type mismatch;
found : Option[Double]
required: Double
val valueOptDouble: Option[java.lang.Double] = Option(rangedValue.getOrElse(nonRangedValue))
I'm sure this could be written much more concisely, but what i'm confused about is why the final line results in this error, as it seems both rangedValue and nonRangedValue are of type Option[Double]
Thanks for any help
The type error is with
rangedValue.getOrElse(nonRangedValue)
because getOrElse here expects Double argument but nonRangedValue is Option[Double]. Perhaps try orElse instead of getOrElse
val valueOptDouble: Option[Double] = rangedValue orElse nonRangedValue
You probably want to take a look at the Scaladoc to learn about useful combinators like map and flatMap
I really, couldn't understand what your code does, so here is an attempt to solve the same problem.
In any case, I believe the code should be easy to adapt to your real needs, but feel free to ask any questions or provide clarification over the problem so I could edit the code.
def getValueFromString(inputValue: String): Option[Double] =
inputValue.split('-').toList match {
case raw1 :: raw2 :: Nil =>
for {
first <- raw1.toDoubleOption
second <- raw2.toDoubleOption
} yield if (first < 60.0d) first else second
case _ =>
None
And then you can pass this method to a flatMap of the original Option[String] like this:
Some("10-30").flatMap(getValueFromString)
// res: Option[Double] = Some(10.0d)
You can see the code running here.
Just do inputValue.split("-").head.toDouble
I have some values provided by the user as Option[String]. I want to validate them only if they are non-empty.
The validation just checks that the string can be converted to an int, and is not less that 0.
Is there any way of simplifying this code, or making it more readable?
val top: Option[String] = ...
val skip: Option[String] = ...
val validationErrors = new ListBuffer[Err]()
top match {
case Some(x) => if (x.toIntOpt.isEmpty || x.toIntOpt.get < 0) validationErrors += PositiveIntegerRequired("$top")
}
skip match {
case Some(x) => if (x.toIntOpt.isEmpty || x.toIntOpt.get < 0) validationErrors += PositiveIntegerRequired("$skip")
}
And here is the toIntOpt helper:
def toIntOpt: Option[Int] = Try(s.toInt).toOption
Yes it can be simplified a lot, by making use of flatMap and for-comprehensions and collect:
def checkInt[A](stringOpt: Option[String], a: A): Option[A] = for {
s <- stringOpt
i <- s.toIntOpt if (i < 0)
} yield a
val validationErrors = List(
checkInt(top, PositiveIntegerRequired("$top")),
checkInt(skip, PositiveIntegerRequired("$skip"))
).collect {
case Some(x) => x
}
The first function checkIntreturns a value a if the original Option was non-empty and contained an invalid negative integer.
Then we put both into a List and collect only the values that are non-empty, resulting in a List of Err with no need for creating an intermediate Buffer.
An even easier way to do something like this can be found with the Validated type found in the cats library: https://typelevel.org/cats/datatypes/validated.html
An alternative to using for-comprehensions is to use a map with a filter.
top.map(toIntOpt)
.filter(i => i.getOrElse(-1) < 0)
.foreach(_ => validationErrors += PositiveIntegerRequired("$top"))
The map call will result in a Option[Option[Int]] which is then filtered based on the value of the nested Option (defaulting to -1 if the option is None).
I have a use case where I need to return a String up to a delimiter String (if found) from an iterator of Char.
The contract:
if iterator is exhausted (only at the begin), return None
if the delimiter String is found, return all characters before it (empty String is fine), delimiter will be dropped
else return the remaining characters
do not eagerly exhaust the iterator!
I do have this working solution, but it feels like Java (which is where I'm coming from)
class MyClass(str: String) {
def nextString(iterator: Iterator[Char]): Option[String] = {
val sb = new StringBuilder
if(!iterator.hasNext) return None
while (iterator.hasNext) {
sb.append(iterator.next())
if (sb.endsWith(str)) return Some(sb.stripSuffix(str))
}
Some(sb.toString())
}
}
Is there a way I can do this in a more functional way (ideally without changing the method signature)?
Update: Here is how I test this
val desmurfer = new MyClass("_smurf_")
val iterator: Iterator[Char] = "Scala_smurf_is_smurf_great_smurf__smurf_".iterator
println(desmurfer.nextString(iterator))
println(desmurfer.nextString(iterator))
println(desmurfer.nextString(iterator))
println(desmurfer.nextString(iterator))
println(desmurfer.nextString(iterator))
println
println(desmurfer.nextString("FooBarBaz".iterator))
println(desmurfer.nextString("".iterator))
Output:
Some(Scala)
Some(is)
Some(great)
Some()
None
Some(FooBarBaz)
None
How about this one:
scala> def nextString(itr: Iterator[Char], sep: String): Option[String] = {
| def next(res: String): String =
| if(res endsWith sep) res dropRight sep.size else if(itr.hasNext) next(res:+itr.next) else res
| if(itr.hasNext) Some(next("")) else None
| }
nextString: (itr: Iterator[Char], sep: String)Option[String]
scala> val iterator: Iterator[Char] = "Scala_smurf_is_smurf_great".iterator
iterator: Iterator[Char] = non-empty iterator
scala> println(nextString(iterator, "_smurf_"))
Some(Scala)
scala> println(nextString(iterator, "_smurf_"))
Some(is)
scala> println(nextString(iterator, "_smurf_"))
Some(great)
scala> println(nextString(iterator, "_smurf_"))
None
scala> println(nextString("FooBarBaz".iterator, "_smurf_"))
Some(FooBarBaz)
What about this one?
def nextString(iterator: Iterator[Char]): Option[String] = {
val t = iterator.toStream
val index = t.indexOfSlice(s)
if(t.isEmpty) None
else if(index == -1) Some(t.mkString)
else Some(t.slice(0,index).mkString)
}
it passed this tests:
val desmurfer = new MyClass("_smurf_")
val iterator: Iterator[Char] = "Scala_smurf_is_smurf_great_smurf__smurf_".iterator
assert(desmurfer.nextString(iterator) == Some("Scala"))
assert(desmurfer.nextString(iterator) == Some("is"))
assert(desmurfer.nextString(iterator) == Some("great"))
assert(desmurfer.nextString(iterator) == Some(""))
assert(desmurfer.nextString(iterator) == None)
assert(desmurfer.nextString("FooBarBaz".iterator) == Some("FooBarBaz"))
assert(desmurfer.nextString("".iterator) == None)
Updated: removed "index == -1 &&" from the first "if condition clause".
This seems to be doing what you'd want. #Eastsun answer motivated me
val str = "hello"
def nextString2(iterator: Iterator[Char]): Option[String] = {
val maxSize = str.size
#tailrec
def inner(collected: List[Char], queue: Queue[Char]): Option[List[Char]] =
if (queue.size == maxSize && queue.sameElements(str))
Some(collected.reverse.dropRight(maxSize))
else
iterator.find(x => true) match {
case Some(el) => inner(el :: collected, if (queue.size == maxSize) queue.dequeue._2.enqueue(el) else queue.enqueue(el))
case None => Some(collected.reverse)
}
if (iterator.hasNext)
inner(Nil, Queue.empty).map(_.mkString)
else
None
}
test(nextString2(Nil.iterator)) === None
test(nextString2("".iterator)) === None
test(nextString2("asd".iterator)) === Some("asd")
test(nextString2("asfhello".iterator)) === Some("asf")
test(nextString2("asehelloasdasd".iterator)) === Some("ase")
But I honestly think it's too complicated to be used. Sometimes you have to use non FP stuff in scala to be performance effecient.
P.S. I didn't know how to match iterator on it's first element, so I've used iterator.find(x => true) which is ugly. Sorry.
P.P.S. A bit of explanation. I recoursively build up collected to fill the elements you are searching for. And I also build queue with last str.size-elements. Then I just check this queue over str each time. This might not be the most efficient way of doing this stuff. You might go with Aho–Corasick algorithm or an analogue if you want more.
P.P.P.S. And I am using iterator as a state, which is probably not FP way
P.P.P.P.S. And you test passes as well:
val desmurfer = new MyClass("_smurf_")
val iterator: Iterator[Char] = "Scala_smurf_is_smurf_great".iterator
test(desmurfer.nextString2(iterator)) === Some("Scala")
test(desmurfer.nextString2(iterator)) === Some("is")
test(desmurfer.nextString2(iterator)) === Some("great")
test(desmurfer.nextString2(iterator)) === None
println()
test(desmurfer.nextString2("FooBarBaz".iterator)) === Some("FooBarBaz")
test(desmurfer.nextString2("".iterator)) === None
Here's one I'm posting just because it's a bit warped :) I wouldn't recommend actually using it:
class MyClass2(str: String) {
val sepLength = str.length
def nextString(iterator: Iterator[Char]): Option[String] = {
if (!iterator.hasNext) return None
val sit = iterator.sliding(sepLength)
val prefix = sit.takeWhile(_.mkString != str).toList
val prefixString = prefix.toList.map(_.head).mkString
if (prefix.head.length < sepLength) Some(prefix.head.mkString)
else if (!iterator.hasNext) Some(prefix.head.mkString + prefix.last.mkString)
else Some(prefixString)
}
}
The idea is that by calling sliding() on our underlying iterator, we can get a sequence, one of which will be our delimiter, if it's present. So we can use takeWhile to find the delimiter. Then the first characters of each of the sliding strings before our delimiter is the string we skipped over. As I said, warped.
I'd really like sliding to be defined so that it produced all subsequences of length n and at the end sequences of length n-1, n-2....1 for this particular use case, but it doesn't, and the horrible if statement at the end is dealing with the various cases.
It passes the test cases :)
Updated: This works without converting the iterator to String
def nextString(iterator: Iterator[Char]): Option[String] = {
if (iterator.isEmpty) None
else Some(iterator.foldLeft("") { (result, currentChar) => if (res.endsWith(str)) result else result + currentChar})
}
A colleague provided the makings of this answer, which is a mixture between his original approach and some polishing from my side. Thanks, Evans!
Then another colleague also added some input. Thanks Ako :-)
class MyClass(str: String) {
def nextString(iterator: Iterator[Char]): Option[String] = {
def nextString(iterator: Iterator[Char], sb: StringBuilder): Option[String] = {
if (!iterator.hasNext || sb.endsWith(str)) {
Some(sb.stripSuffix(str))
} else {
nextString(iterator, sb.append(iterator.next()))
}
}
if (!iterator.hasNext) None
else nextString(iterator, new StringBuilder)
}
}
So far, I like this approach best, so I will accept it in two days unless there is a better answer by then.
I have to validate some variables manually for some reason and return a map with the sequance of the error messages for each variable. I've decided to use mutable collections for this because I think there is no other choise left:
val errors = collection.mutable.Map[String, ListBuffer[String]]()
//field1
val fieldToValidate1 = getData1()
if (fieldToValidate1 = "")
errors("fieldToValidate1") += "it must not be empty!"
if (validate2(fieldToValidate1))
errors("fieldToValidate1") += "validation2!"
if (validate3(fieldToValidate1))
errors("fieldToValidate1") += "validation3!"
//field2
val fieldToValidate2 = getData1()
//approximately the same steps
if (fieldToValidate2 = "")
errors("fieldToValidate2") += "it must not be empty!"
//.....
To my mind, it look kind of clumsy and there should other elegant solution. I'd also like to not use mutable collections if possible. Your ideas?
Instead of using mutable collections, you can define errors with var and update it in this way.
var errors = Map[String, List[String]]().withDefaultValue(Nil)
errors = errors updated ("fieldToValidate1", errors("fieldToValidate1") ++ List("it must not be empty!"))
errors = errors updated ("fieldToValidate1", errors("fieldToValidate1") ++ List("validation2"))
The code looks more tedious, but it gets out of mutable collections.
So what is a good type for your check? I was thinking about A => Option[String] if A is the type of your object under test. If your error messages do not depend on the value of the object under test, (A => Boolean, String) might be more convenient.
//for constructing checks from boolean test and an error message
def checkMsg[A](check: A => Boolean, msg: => String): A => Option[String] =
x => if(check(x)) Some(msg) else None
val checks = Seq[String => Option[String]](
checkMsg((_ == ""), "it must not be empty"),
//example of using the object under test in the error message
x => Some(x).filterNot(_ startsWith "ab").map(x => x + " does not begin with ab")
)
val objectUnderTest = "acvw"
val errors = checks.flatMap(c => c(objectUnderTest))
Error labels
As I just noted, you were asking for a map with a label for each check. In this case, you need to provide the check label, of course. Then the type of your check would be (String, A => Option[String]).
Although a [relatively] widespread way of doing-the-thing-right would be using scalaz's Validation (as #senia has shown), I think it is a little bit overwhelming approach (if you're bringing scalaz to your project you have to be a seasoned scala developer, otherwise it may bring you more harm than good).
Nice alternative could be using ScalaUtils which has Or and Every specifically made for this purpose, in fact if you're using ScalaTest you already have seen an example of them in use (it uses scalautils underneath). I shamefully copy-pasted example from their doc:
import org.scalautils._
def parseName(input: String): String Or One[ErrorMessage] = {
val trimmed = input.trim
if (!trimmed.isEmpty) Good(trimmed) else Bad(One(s""""${input}" is not a valid name"""))
}
def parseAge(input: String): Int Or One[ErrorMessage] = {
try {
val age = input.trim.toInt
if (age >= 0) Good(age) else Bad(One(s""""${age}" is not a valid age"""))
}
catch {
case _: NumberFormatException => Bad(One(s""""${input}" is not a valid integer"""))
}
}
import Accumulation._
def parsePerson(inputName: String, inputAge: String): Person Or Every[ErrorMessage] = {
val name = parseName(inputName)
val age = parseAge(inputAge)
withGood(name, age) { Person(_, _) }
}
parsePerson("Bridget Jones", "29")
// Result: Good(Person(Bridget Jones,29))
parsePerson("Bridget Jones", "")
// Result: Bad(One("" is not a valid integer))
parsePerson("Bridget Jones", "-29")
// Result: Bad(One("-29" is not a valid age))
parsePerson("", "")
// Result: Bad(Many("" is not a valid name, "" is not a valid integer))
Having said this, I don't think you can do any better than your current approach if you want to stick with core scala without any external dependencies.
In case you can use scalaz the best solution for aggregation errors is Validation:
def validate1(value: String) =
if (value == "") "it must not be empty!".failNel else value.success
def validate2(value: String) =
if (value.length > 10) "it must not be longer than 10!".failNel else value.success
def validate3(value: String) =
if (value == "error") "it must not be equal to 'error'!".failNel else value.success
def validateField(name: String, value: String): ValidationNel[(String, String), String] =
(
validate1(value) |#|
validate2(value) |#|
validate3(value)
).tupled >| value leftMap { _.map{ name -> _ } }
val result = (
validateField("fieldToValidate1", getData1()) |#|
validateField("fieldToValidate2", getData2())
).tupled
Then you could get optional errors Map like this:
val errors =
result.swap.toOption.map{
_.toList.groupBy(_._1).map{ case (k, v) => k -> v.map(_._2) }
}
// Some(Map(fieldToValidate2 -> List(it must not be equal to 'error'!), fieldToValidate1 -> List(it must not be empty!)))
I'm still fairly new to Scala, and I'm discovering new and interesting ways for doing things on an almost daily basis, but they're not always sensible, and sometimes already exist within the language as a construct and I just don't know about them. So, with that preamble, I'm checking to see if a given string is comprised entirely of digits, so I'm doing:
def isAllDigits(x: String) = x.map(Character.isDigit(_)).reduce(_&&_)
is this sensible or just needlessly silly? It there a better way? Is it better just to call x.toInt and catch the exception, or is that less idiomatic? Is there a performance benefit/drawback to either?
Try this:
def isAllDigits(x: String) = x forall Character.isDigit
forall takes a function (in this case Character.isDigit) that takes an argument that is of the type of the elements of the collection and returns a Boolean; it returns true if the function returns true for all elements in the collection, and false otherwise.
Do you want to know if the string is an integer? Then .toInt it and catch the exception. Do you instead want to know if the string is all digits? Then ask one of:
s.forall(_.isDigit)
s matches """\d+"""
You also may consider something like this:
import scala.util.control.Exception.allCatch
def isLongNumber(s: String): Boolean = (allCatch opt s.toLong).isDefined
// or
def isDoubleNumber(s: String): Boolean = (allCatch opt s.toDouble).isDefined
You could simply use a regex for this.
val onlyDigitsRegex = "^\\d+$".r
def isAllDigits(x: String) = x match {
case onlyDigitsRegex() => true
case _ => false
}
Or simply
def isAllDigits(x: String) = x.matches("^\\d+$")
And to improve this a little bit, you can use the pimp my library pattern to make it a method on your string:
implicit def AllDigits(x: String) = new { def isAllDigits = x.matches("^\\d+$") }
"12345".isAllDigits // => true
"12345foobar".isAllDigits // => false
Starting Scala 2.13 we can use String::toDoubleOption, to determine whether a String is a decimal number or not:
"324.56".toDoubleOption.isDefined // true
"4.06e3".toDoubleOption.isDefined // true
"9w01.1".toDoubleOption.isDefined // false
Similar option to determine if a String is a simple Int:
"324".toIntOption.isDefined // true
"à32".toIntOption.isDefined // false
"024".toIntOption.isDefined // true
import scala.util.Try
object NumCruncher {
def isShort(aString: String): Boolean = Try(aString.toLong).isSuccess
def isInt(aString: String): Boolean = Try(aString.toInt).isSuccess
def isLong(aString: String): Boolean = Try(aString.toLong).isSuccess
def isDouble(aString: String): Boolean = Try(aString.toDouble).isSuccess
def isFloat(aString: String): Boolean = Try(aString.toFloat).isSuccess
/**
*
* #param x the string to check
* #return true if the parameter passed is a Java primitive number
*/
def isNumber(x: String): Boolean = {
List(isShort(x), isInt(x), isLong(x), isDouble(x), isFloat(x))
.foldLeft(false)(_ || _)
}
}
Try might not performance-wise be the optimal choice, but otherwise it's neat:
scala> import scala.util.Try
scala> Try{ "123x".toInt }
res4: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "123x")
scala> Try{ "123x".toInt }.isSuccess
res5: Boolean = false
#Jesper's answer is spot on.
Do NOT do what I'm suggesting below (explanation follows)
Since you are checking if a given string is numeric (title states you want a decimal), the assumption is that you intend to make a conversion if the forall guard passes.
A simple implicit in scope will save a whopping 9 key strokes ;-)
implicit def str2Double(x: String) = x.toDouble
Why this is dangerous
def takesDouble(x: Double) = x
The compiler will now allow takesDouble("runtime fail") since the implicit tries to convert whatever string you use to Double, with zero guarantee of success, yikes.
implicit conversions then seem better suited to situations where an acceptable default value is supplied on conversion failure (which is not always the case; therefore implicit with caution)
Here is one more:
import scala.util.Try
val doubleConverter: (String => Try[Double]) = (s: String) => Try{ s.map(c => if ((Character.isDigit(c) == true) || (c == '.')) Some(c) else None).flatten.mkString.toDouble }
val d1: Try[Double] = doubleConverter("+ 1234.0%")
val d2: Try[Double] = doubleConverter("+ 1234..0%")
Based on brilliant Jexter's solution, in this piece of code I take care of the NullPointerException using Option:
def isValidPositiveNumber(baseString: Option[String]): Boolean = baseString match {
case Some(code) => !code.isEmpty && (code forall Character.isDigit)
case None => false
}