Im a beginner at a scala and am looking for the best/idiomatic way to do what I intend to do here.
This is what I want to do
def someMethod(obj:MyObj):List[String] = {
List[String]() +:
{if (somecondition is satisfied) .. " element"} +:
{ if (another condition) .. " something else " }
}
That is the method checks some properties of the input parameter object and adds elements to the List (that is to be returned) . If none of the conditions are satisfied , it should return an empty List.
And 2. Please tell me the right way to do this Scala . If I were iterating over a list of conditions, I could have used comprehensions.
Rather than filtering Unit, I would rather use unary or empty lists:
def someMethod(obj:MyObj): List[String] = {
Nil ++
( if (somecondition is satisfied) List(" element") else Nil ) ++
( if (another condition) .. List(" something else ") else Nil ) ++
}
EDIT: Concerning your comment below, if you find the above code too verbose and hard to maintain, you can still create a helper function:
def optElem[T]( condition: Boolean)( value: => T ): Option[T] = if ( condition ) Option( value ) else None
def someMethod(obj:MyObj): List[String] = {
Nil ++
optElem (somecondition is satisfied)( " element") ++
optElem (another condition)(" something else " )
}
if
- else
is an expression in Scala. What you have written becomes:
List[String]() +:
{if (somecondition is satisfied) {" element"; () } else () }+:
{ if (another condition) { " something else "; () } else () }
As you can see, the common branch type is Unit
.
The type of the whole expression would be List[Any]
since that's the common supertype of String
and Unit
.
Some ways to achieve what you want:
// #1. Ugly.
def someMethod(obj:MyObj):List[String] = {
val xs = List[String]()
val xs1 = if (somecondition is satisfied) xs :+ " element" else xs
val xs2 = if (another condition) xs1 :+ " something else" else xs1
xs2
}
// #2. Better, but uses mutable builder.
def someMethod(obj:MyObj):List[String] = {
val b = List.newBuilder[String]
if (somecondition is satisfied) b += " element"
if (another condition) b += " something else"
b.result
}
// #3. Best way IMO, but computationally expensive.
def someMethod(obj:MyObj):List[String] = {
List[String]() ++
Option("element").filter(some condition) ++ // for more correct semantics
// use LazyOption from Scalaz.
Option("something else").filter(another condition)
}
You may write it like this:
def someMethod(obj:MyObj):List[String] = {
List(
if (somecondition is satisfied) " element",
if (another condition) " something else "
) collect{ case x: String => x }
}
Suppose all conditions are failed: you'll end up with List(Unit,Unit)
first which will be filtered by type. Unit doesn't satisfy type condition inside collect, so result will be empty List of Strings
The good thing is that unlike filter
method collect
chooses as tight type as it can (so you'll get Sequence of Strings -- this will be infered from function inside collect).
Another possibility is to replace .collect { ... }
with flatten
, but you'll lose type information.
Another take on this is to construct a list of options then flatten the list.
def f(obj: MyObj): List[String] = {
List(if (cond1(obj)) Some("element") else None,
if (cond2(obj)) Some("something else") else None).flatten
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.