In Ruby I often like to handle null values from collections with the following function:
def nilstuff(a,stuff="")
if(a.nil?)
return stuff
else
return a
end
end
In Scala there is an annoyance that empty values in collections throw exceptions, not nil:
val myMap = Map[String, String]()
myMap += ("Apple" -> "Plant")
myMap += ("Walrus" -> "Animal")
println(myMap("Elephant"))
//Exception in thread "main" java.lang.ExceptionInInitializerError
// at MyProgram.main(MyProgram.scala)
//Caused by: java.util.NoSuchElementException: key not found: Elephant
Is there a way to make a similar function in Scala that handles exceptions and returns the "stuff" instead?
println(missing_stuff(myMap("Elephant"),"Unknown"))
You can add a default value to your Map:
scala> import scala.collection.mutable.Map
import scala.collection.mutable.Map
scala> val myMap = Map[String, String]().withDefaultValue("Unknown")
myMap: scala.collection.mutable.Map[String,String] = Map()
scala> myMap("foo")
res0: String = Unknown
Another option is the getOrElse method of Map.
Or apply a pattern match to the result of get:
myMap.get("foo") match {
case Some(value) => useAsDesired(value)
case None => useAsDesired("Unknown")
}
The last might be the most general solution to what your title calls "Clean exception handling."
There are several ways built in.
(1) Don't get the value, get an option.
myMap.get("Elephant")
Now that you have an Option, you can do all sorts of things with it (including get either its contents or a default value if there is none):
myMap.get("Elephant").getOrElse("")
(2) Get the value, or a default value if it's not there
myMap.getOrElse("Elephant", "")
(3) Create the map with a default value (warning--this will not survive filtering, mapping, or any other handy collections operations). Immutably you'd add this after you were done building the map:
val defaultMap = myMap.withDefault(_ => "")
defaultMap("Elephant")
With a mutable map, you might add it at the beginning:
val myMap = new collection.mutable.HashMap[String,String].withDefaultValue("")
(4) Add the item that you're missing when you find it not there (mutable maps only):
myMap.getOrElseUpdate("Elephant", "Dumbo")
Probably not what you want in this particular case, but often useful.
Related
I have an EdmPortfolio type that has id (int), name (String) and tags which is a map as its members.
EdmPortfolio say has an id 1, and name as Portfolio1 and Map could have the following values,
analyst, John
region, US
I have a List, At the end i want to have a Map which has all the map values combined from all portfolios. Another EdmPortfolio might have the id as 2, name as Portfolio2 and Map with values analyst, Smith
region , UK
I want to have a combined Map with Values
region 'US','UK'
analyst 'John','Smith'
analyst and region are the keys to the map.
It has both the maps combined. I have the following code but i am a little lost
List<Map<Tag,String>> portfolioTagsList = new ArrayList<>();
for (EdmPortfolio edmPortfolio : edmPortfolioList) {
Map<Tag,String> portfolioTags = edmPortfolio.getPortfolioTags().entrySet()
.stream()
.filter(e -> (e.getValue() != ""|| e.getValue() !=null))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue
));
portfolioTagsList.add(portfolioTags);
}
Map<Tag,String> finalTags = portfolioTagsList.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.joining(",",Map.Entry::getValue)));
I am getting nonstatic method cannot be referenced from static context. How do i achieve this?
Thanks for your time
I'd do something like:
Map<Tag,String> finalTags = edmPortfolioList.stream()
.flatMap(edmPortfolio -> edmPortfolio.getPortfolioTags().entrySet().stream())
.filter(e -> (e.getValue() != "" || e.getValue() !=null)) // this seems weird, but just keeping
.collect(Collectors.groupingBy(e -> e.getKey(),
Collectors.mapping(ev -> ev.getValue(),
Collectors.joining(",")));
BTW: Any reason to break that in two streams?
Unfortunately, “nonstatic method cannot be referenced from static context” is the error that javac often ends up when type inference fails, especially in the context of method references or lambda expressions. The actual cause could be a wrong generic type parameter, a forgotten import statement, the use of a lambda expression or method reference at an inappropriate place, or even a misplaced or forgotten brace somewhere.
In your case, it’s Collectors.joining(",",Map.Entry::getValue) as that collector has no parameter of a function type that could accept a method reference.
You should use Collectors.mapping(Map.Entry::getValue, Collectors.joining(",")) instead.
Besides that, follow BrunoJCM’s suggestion to use a single stream operation and pay attention to the filter condition. e.getValue() != "" || e.getValue() !=null makes no sense as a reference can never be both, a reference to "" and the null reference, hence, this condition is always fulfilled. You most likely wanted to express that the string must not be null and not an empty string. In this regard, you should not compare strings by reference but use equals. For testing for an empty string, there is the alternative to use isEmpty() instead of equals(""). So the condition should be e.getValue()!=null && !e.getValue().isEmpty(). Mind the order, as we can invoke isEmpty() only after having verified that it is not null.
I have a fairly simple javascript method
(props,propName,componentName) => {
var value = props[propName];
const getOrSpread = name =>
props[name] || props.spread && props.spread[name];
// remainder of function code omitted
}
that is working in javascript land. I'm trying to convert it to fable but either I can get it to have a definitely exists property access to .spread or dynamic access to props[propName] but not both
module JsxHelpers =
type IReactProps =
abstract member spread : obj
let isfuncOrNullPropType (props:IReactProps) (propName:string) componentName =
let propsO :obj = box props
let value:obj = propsO?propName
let valueAttempt2:obj = (box props)?(propName)
// rest of translation not attempted yet
value
where if props is defined as IReactProps, then .spread works, but neither of the two possible let value lines compile.
or props is defined as obj and it says `This expression was expected to have type 'obj' but here has type ''a -> obj'
even the simplest object from the documentation doesn't appear to compile:
let isfuncOrNullPropType (props:obj) (propName:string) =
let value2:obj = props?propName
value2
using "fable-core": "^1.0.0-narumi-905"
You definitely need to put the prop name in parentheses according to the documentation. The compiler error you're getting is because props?(propName) returns type 'a -> obj. Apparently, the dynamic (?) operator returns an Applicable, and from the fable source:
/// DO NOT USE: Internal type for Fable dynamic operations
type Applicable = obj->obj
Perhaps try:
let value : obj = unbox<obj> (props?(propName))
I want to unpersist myRDD after the data is saved. I have the following code:
val isDone = myRDD.saveAsTextFile("myOutput")
if (isDone != null) {
myRDD.unpersist()
}
but the line:
isDone != null
keeps saying: comparing values of types Unit and Null using `!=' will always yield true
What should be the correct way to solve this problem? Thank you!
This should work fine:
myRDD.saveAsTextFile("myOutput")
myRDD.unpersist()
The data will be saved before the RDD is unpersisted.
Note that the saveAsTextFile method returns Unit. This is a type that is returned by any method (procedure) which does not return anything useful, and there is only one instance, i.e. (). So nothing useful is achieved by testing on the value returned by saveAsTextFile. Also, Unit being a subtype of AnyVal can never be equal to null, that's why you're getting the particular error that you're seeing. The same thing happens for Ints:
def foo(x: Int) = x != null
I would like to write a subclass of pandas.core.index.Index. I'm following the guide to subclassing ndarrays which can be found in the numpy documentation. Here's my code:
import numpy as np
import pandas as pd
class InfoIndex(pd.core.index.Index):
def __new__(subtype, data, info=None):
# Create the ndarray instance of our type, given the usual
# ndarray input arguments. This will call the standard
# ndarray constructor, but return an object of our type.
# It also triggers a call to InfoArray.__array_finalize__
obj = pd.core.index.Index.__new__(subtype, data)
# set the new 'info' attribute to the value passed
obj.info = info
# Finally, we must return the newly created object:
return obj
However, it doesn't work; I only get a Index object:
In [2]: I = InfoIndex((3,))
In [3]: I
Out[3]: Int64Index([3])
What am I doing wrong?
Index constructor tries to be clever when the inputs are special (all ints or datetimes for example) and skips to calls to view at the end. So you need to put that in explicitly:
In [150]: class InfoIndex(pd.Index):
.....: def __new__(cls, data, info=None):
.....: obj = pd.Index.__new__(cls, data)
.....: obj.info = info
.....: obj = obj.view(cls)
.....: return obj
.....:
In [151]: I = InfoIndex((3,))
In [152]: I
Out[152]: InfoIndex([3])
Caveat emptor: be careful subclassing pandas objects as many methods will explicitly return Index as opposed to the subclass. And there are also features in sub-classes of Index that you'll lose if you're not careful.
If you implement the __array_finalize__ method you can ensure that metadata is preserved in many operations. For some index methods you'll need to provide implementations in your subclass. See http://docs.scipy.org/doc/numpy/user/basics.subclassing.html for a bit more help
To expand on the previous answers. You can also preserve most index methods, if you use the _constructor property and set _infer_as_myclass = True.
(Note: I'm using Scala 2.7.7 here, not 2.8).
I'm doing something pretty simple -- creating a map based on the values in a simple, 2-column CSV file -- and I've completed it easily enough, but I'm perplexed at why my first attempt didn't compile. Here's the code:
// Returns Iterator[String]
private def getLines = Source.fromFile(csvFilePath).getLines
// This doesn't compile:
def mapping: Map[String,String] = {
Map(getLines map { line: String =>
val pairArr = line.split(",")
pairArr(0) -> pairArr(1).trim()
}.toList:_*)
}
// This DOES compile
def mapping: Map[String,String] = {
def strPair(line: String): (String,String) = {
val pairArr = line.split(",")
pairArr(0) -> pairArr(1).trim()
}
Map(getLines.map( strPair(_) ).toList:_*)
}
The compiler error is
CsvReader.scala:16:
error: value toList is not a member of
(St ring) => (java.lang.String,
java.lang.String) [scalac] possible
cause: maybe a semicolon is missing
before `value toList'? [scalac]
}.toList:_*) [scalac] ^
[scalac] one error found
So what gives? They seem like they should be equivalent to me, apart from the explicit function definition (vs. anonymous in the nonworking example) and () vs. {}. If I replace the curly braces with parentheses in the nonworking example, the error is "';' expected, but 'val' found." But if I remove the local variable definition and split the string twice AND use parens instead of curly braces, it compiles. Can someone explain this difference to me, preferably with a link to Scala docs explaining the difference between parens and curly braces when used to surround method arguments?
Looks like the difference is because you are using the operator notation in the first example. If you add an extra set of parentheses it works:
def mapping: Map[String,String] = {
Map((getLines map { line: String =>
val pairArr = line.split(",")
pairArr(0) -> pairArr(1).trim()
}).toList:_*)
}
or if you don't use the operator syntax it works
def mapping: Map[String,String] = {
Map(getLines.map({ line: String =>
val pairArr = line.split(",")
pairArr(0) -> pairArr(1).trim()
}).toList:_*)
}
I think the problem is that using the normal method invocation syntax has higher precedence than the operator syntax for method calls. This meant that the .toList was being applied to the anonymous function rather than to the result of the map method call.
If you don't use operator syntax, it compiles fine:
//Compiles
def mapping: Map[String,String] = {
Map(getLines.map { line: String =>
val pairArr = line.split(",")
pairArr(0) -> pairArr(1).trim()
}.toList:_*)
}
There is not a problem with how you use the anonymous function, but as Ben mentioned, the syntax of calls map without the . is not equivalent to the typical Java-style method call.