hashmap with regexp as key, groovy/java - regex

I`ve encountered a problem:
Is it possible, to use regexp as a key in hashmap?
For example:
def unitsMap=[
(~/(?i).*ABC.*nM.*/):'AAA',
(~/(?i).*DEF.*nM.*/):'DDD'
]
println unitsH3HashMap['ABC (122344345P)']
Of course, that returns null value.
Best regards

No, but you can use it in a switch:
def unitsMap(key) {
switch(key) {
case ~/(?i).*ABC.*/: return 'AAA'
case ~/(?i).*DEF.*/: return 'DDD'
}
}
println unitsMap('ABC (122344345P)')

In order to get what you want you would have to write your own implementation of Map that uses pattern matching to perform getAt, putAt, contains, etc. However, it seems to me that the algorithmic complexity for lookups in such a scenario would always be O(n). Not very good compared to HashMap (O(0)) or TreeMap (O(log n)).
#tim_yates 's solution solves the raw outline of the problem as presented, but would not allow you to add new keys (cases) on-the-fly, as would your original desired code. If on-the-fly changes to your "map" are not important to you, then you should definitely use his solution (which I will endorse by giving it +1 now). If not, the you might be able to adapt his code to generate and invoke a script from a Map that will do what you desire.
This script:
// generate unitMapper
def generateUnitMapper(baseMap) {
def script = '''{ key ->
switch (key) {
'''
script += baseMap.collect { k, v ->
""" case ~/${k}/: return '${v}'
"""
}.join("")
script += ''' default: return null
}
}
'''
}
// notice this map is just using the regular expression STRINGS as keys,
// not the PATTERN objects from the original poster's code
def starterMap = [
/(?i).*ABC.*[\dA-Z]+.*/:'AAA',
/(?i).*DEF.*[\dA-Z]+.*/:'DDD'
]
def closureScript = generateUnitMapper(starterMap)
def unitsClosure = Eval.me(closureScript)
println closureScript
println unitsClosure('ABC (122344345P)')
println()
// regenerate map and closure and rerun
def changedMap = [ /ABC .*/:'000' ] + starterMap
closureScript = generateUnitMapper(changedMap)
unitsClosure = Eval.me(closureScript)
println closureScript
println unitsClosure('ABC (122344345P)')
Yields this output:
{ key ->
switch (key) {
case ~/(?i).*ABC.*[\dA-Z]+.*/: return 'AAA'
case ~/(?i).*DEF.*[\dA-Z]+.*/: return 'DDD'
default: return null
}
}
AAA
{ key ->
switch (key) {
case ~/ABC .*/: return '000'
case ~/(?i).*ABC.*[\dA-Z]+.*/: return 'AAA'
case ~/(?i).*DEF.*[\dA-Z]+.*/: return 'DDD'
default: return null
}
}
000

Related

What's an idiomatic way to traverse and update data structures functionally in Scala?

I'm coming from a Python-heavy background and trying to learn Scala through a basic "Design a Parking Lot" exercise. I have Scala code that looks something like:
class ParkingLot(spaces: Set[ParkingSpace]) {
var openSpaces: Set[ParkingSpace] = spaces;
var usedSpaces: Set[ParkingSpace] = Set()
def assign(vehicle: Vehicle): Boolean = {
var found = false;
for (s <- openSpaces) {
(s.isCompatibleWithVehicle(vehicle)) match {
case true => {
if (!found) {
s.acceptVehicle(vehicle)
openSpaces -= s
usedSpaces += s
found = true
}
}
case _ => {}
}
}
found
}
}
The logic is pretty simple - I have a ParkingLot with Sets of open and occupied ParkingSpaces. I want to define a function assign that takes in a Vehicle, loops through all the openSpaces and if it finds an available space, will update the open and used spaces. I'm having a hard time coming up with a good idiomatic way to do this. Any thoughts and suggestions about how to reframe questions into a Scala mindset?
The main problem with this code is use of mutable state (var). Rather than changing an existing object, functional code creates new, modified objects. So the functional approach is to create a new ParkingLot each time with the appropriate allocation of spaces.
case class ParkingLot(open: Set[ParkingSpace], used: Set[ParkingSpace])
{
def assignVehicle(vehicle: Vehicle): Option[ParkingLot] =
open.find(_.isCompatibleWithVehicle(vehicle)).map { space =>
ParkingLot(open - space, used + space.acceptVehicle(vehicle))
}
}
assignVehicle can return a new parking lot with the spaces appropriately updated. It returns an Option because there might not be a compatible space, in which case it returns None. The caller can take whatever action is necessary in this case.
Note that ParkingSpace now as an acceptVehicle that returns a new ParkingSpace rather than modifying itself.
As also the answer by #Tim mentioned, you need to avoid mutations, and try to handle this kind of state managements in functions. I'm not gonna dive into the details since Tim mentioned some, I'm just proposing a new approach to the implementation, which uses a map of spaces to weather they're used, and returns a new (not optional) instance every time you assign a new vehicle (if the vehicle fits in, updated instance is returned, and if not, the same instance):
class ParkingLot(spaces: Map[ParkingSpace, Boolean]) {
def withVehicleAssigned(vehicle: Vehicle): ParkingLot =
spaces.collectFirst {
case (space, used) if !used && space.isCompatibleWithVehicle(vehicle) =>
new ParkingLot(spaces.updated(space, true))
}.getOrElse(this)
}
Almost the same process goes for removing vehicles, the usage would be something like this:
parkingLot
.withVehicleAssigned(v1)
.withVehicleAssigned(v2)
.withVehicleRemoved(v1)
Since most answers already explained the importance of immutability and creating new objects, I am just going to propose two alternative models and solutions.
1. Using a queue of empty spaces plus a set of used ones.
final case class ParkingLot(freeSpaces: List[ParkingSpace], occupiedSpaces: Set[ParkingSpace]) {
// Returns the used space and the new parking lot.
// An option is used since the parking lot may be full.
def assign(vehicle: Vehicle): Option[(ParkingSpace, ParkingLot)] =
freeSpaces match {
case freeSpace :: remainingSpaces =>
val usedSpace = freeSpace.withVehicle(vehicle)
Some(copy(freeSpaces = remainingSpaces, usedSpaces = usedSpace + usedSpaces))
case Nil =>
None
}
}
2. Using a List[(ParkingSpace, Boolean)] and a tail-recursive function.
final case class ParkingLot(parkingSpaces: List[(ParkingSpace, Boolean)]) {
// Returns the used space and the new parking lot.
// An option is used since the parking lot may be full.
def assign(vehicle: Vehicle): Option[(ParkingSpace, ParkingLot)] = {
#annotation.tailrec
def loop(remaining: List[(ParkingSpace, Boolean)], acc: List[(ParkingSpace, Boolean)]): Option[(ParkingSpace, List[(ParkingSpace, Boolean)])] =
remaining match {
case (parkingSpace, occupied) :: tail =>
if (occupied) loop(remaining = tail, (parkingSpace, occupied) :: acc)
else {
val usedSpace = parkingSpace.withVehicle(vehicle)
val newSpaces = acc reverse_::: ((usedSpace -> true) :: tail)
Some(usedSpace -> newSpaces)
}
case Nil =>
None
}
loop(remaining = parkingSpaces, acc = List.empty).map {
case (usedSpace, newSpaces) =>
usedSpace -> copy(newSpaces)
}
}
}
Note, the boolean may be redundant since the ParkingSpace should be able to tell us if it is empty or not.

Does groovy have a built-in way to walk / transform a data structure?

Given a nested map/list/scalar data structure in Groovy, does it have any pretty "Groovy" way to walk it and produce a transformed structure?
The cleanest way I've written so far isn't too bad, a recursive walker that applies a closure. But I'd welcome advice if there's a built-in way I am missing.
For example, take this data structure and replace all instances of ${VARIABLE} with REPLACED in Strings within it:
def config = [
'${VARIABLE}: 'scalar',
'foo': [
'bar': 1,
'baz': ['a', 'b', 'c', 'd'],
'my_${VARIABLE}_key': null
],
'bak': 1,
'ban': 'abcd',
'boo': [
['x': 1, 'y': 2, 'subst': '${VARIABLE}'],
['a': 1, 'b': 2]
]
]
Here's the best I've come up with so far:
def walk(v, Closure transform ) {
switch (v) {
case null:
return null
case Map:
return v.collectEntries { mk, mv -> [ transform(mk), walk(mv, transform) ] }
case List:
return v.collect { lv -> walk(lv, transform) }
default:
return transform(v)
}
}
which given the above example data, may be applied like:
def engine = new groovy.text.SimpleTemplateEngine()
def subs = ['VARIABLE': 'REPLACED']
def newconfig = walk(config) { v ->
switch (v) {
case String:
return engine.createTemplate(v).make(subs)
default:
return v
}
}
This relies on Groovy's smart switch statement. It's not extensible, you can't just plug in your own type handlers, but it's so simple you don't need to. It does a hybrid copy by default, making new instances of Lists and Maps but retaining references to the original scalar or unmatched types. It can be made to deep copy too, per the following identity transform examples:
// Identity transform, shallow copy scalars
assert (config == (walk(config) { v -> v.clone() }))
// Identity transform, deep copy scalars where possible
assert (config == (walk(config) {
v ->
try {
return v.clone()
} catch (java.lang.CloneNotSupportedException ex) {
return v
}
}))
Thoughts? Better ways?

Compressing series of if-else statement in Groovy

I have a series of if-else statements in Groovy:
String invoke = params?.target
AuxService aux = new AuxService()
def output
if(invoke?.equalsIgnoreCase("major")) {
output = aux.major()
}
else if(invoke?.equalsIgnoreCase("minor")) {
output = aux.minor()
}
else if(invoke?.equalsIgnoreCase("repository")) {
output = aux.repository()
}
...
else if(invoke?.equalsIgnoreCase("temp")) {
output = aux.temp()
}
else {
output = aux.propagate()
}
The ellipsis contains yet another 14 sets of if-else statements, a total of 19. You see, depending on the value of invoke the method that will be called from AuxService. Now I'm thinking the following to reduce the lines:
String invoke = params?.target()
AuxService aux = new AuxService()
def output = aux?."$invoke"() ?: aux.propagate()
But I think the third line might not work, it looks very unconventional. And just a hunch, I think that line is prone to error. Is this a valid code or are there any more optimal approach to compress these lines?
Just test String invoke before using it. Note that aux won't be null, so no need to use safe navigation (?.).
class AuxService {
def major() { 'major invoked' }
def minor() { 'minor invoked' }
def propagate() { 'propagate invoked' }
}
def callService(invoke) {
def aux = new AuxService()
return invoke != null ? aux.invokeMethod(invoke, null) : aux.propagate()
}
assert callService('major') == 'major invoked'
assert callService(null) == 'propagate invoked'
Note this is will fail if the input doesn't contain a valid method in class AuxService.
Firstly, your code is avlid in Groovy. Though, if equalsIgnoreCase is required, your reduced code will not work. The same for if params is null, since then invoke would be null. But I think your basic idea is right. So what I would do is making a map (final static somewhere) with the methods in uppercase as String key and the real method in correct casing as String value. Then you can use that to ensure correctness for different cases. Null handling I would solve separate:
def methodsMap = ["MAJOR":"major",/* more mappings here */]
String invoke = params?.target()
AuxService aux = new AuxService()
def methodName = methodsMap[invoke?.toUpperCase()]
def output = methodName ? aux."$methodName"() : aux.propagate()
An slightly different approach would be to use Closure values in the map. I personally find that a bit overkill, but it allows you to do more than just the plain invocation
def methodsMap = ["MAJOR":{it.major()},/* more mappings here */]
String invoke = params?.target()
AuxService aux = new AuxService()
def stub = methodsMap[invoke?.toUpperCase()]
def output = stub==null ? stub(aux) : aux.propagate()
I thought about using the Map#withDefault, but since that will create a new entry I decided not to. It could potentially cause memory problems. In Java8 you can use Map#getOrDefault:
String invoke = params?.target()
AuxService aux = new AuxService()
def methodName = methodsMap.getOrDefault(invoke?.toUpperCase(), "propagate")
def output = aux."$methodName"()
The Elvis operator is used to shorten the equivalent Java ternary operator expression.
For example,
def nationality = (user.nationality!=null) ? user.nationality : "undefined"
can be shortened using the Elvis operator to
def nationality = user.nationality ?: "undefined"
Note that the Elvis operator evaluates the expression to the left of the "?" symbol. If the result is non-null, it returns the result immediately, else it evaluates the expression on the right of the ":" symbol and returns the result.
What this means is that you cannot use the Elvis operator to perform some extra logic on the right side of the "?" symbol if the condition evaluates to true. So, the ternary expression
user.nationality ? reportCitizen(user) : reportAlien(user)
cannot be (directly)expressed using the Elvis operator.
Coming back to the original question, the Elvis operator cannot be (directly) applied to checking if a method exists on an object and invoking it if present. So,
def output = aux?."$invoke"() ?: aux.propagate()
will not work as expected, because the Elvis operator will try to evaluate "aux?."$invoke"()" first. If "invoke" refers to a method that does not exist, you will get a MissingMethodException.
One way I can think of to work around this is -
class AuxService {
def major() { println 'major invoked' }
def minor() { println 'minor invoked' }
def propagate() { println 'propagate invoked' }
}
def auxService = new AuxService()
def allowedMethods = ["major", "minor", "propagate"]
def method = null
allowedMethods.contains(method?.toLowerCase()) ? auxService."${method?.toLowerCase()}"() : auxService.propagate() // Prints "propagate invoked"
method = "MaJoR"
allowedMethods.contains(method?.toLowerCase()) ? auxService."${method?.toLowerCase()}"() : auxService.propagate() // Prints "major invoked"
method = "undefined"
allowedMethods.contains(method?.toLowerCase()) ? auxService."${method?.toLowerCase()}"() : auxService.propagate() // Prints "propagate invoked"
In a nutshell, store the list of invoke-able methods in a list and check to see if we're trying to invoke a method from this list. If not, invoke the default method.

Using dict like C switch

class checkevent:
def __init__(self,fromuser):
self.fromuser = fromuser
def openid_check(self):# use sqlalchemy
exist_user = User.query.filter_by(openid = self.fromuser).first()
if exist_user is None:
text = u'请绑定后在使用'
return text
def grade(self):
openid_check()
exist_user = User.query.filter_by(openid = self.fromuser).first()
geturp = urp(exist_user.username, exist_user.password_urp) #the function
return geturp #return the grades as text
def key_check(self,x): # use dict like switch
{'grade': self.grade
}
contents = checkevent('ozvT4jlLObJWzz2JQ9EFsWSkdM9U').key_check('grade')
print contents
It's always return None,I want to get a value
and it's the right way to use dict?
There's no return statement in key_check, so naturally it doesn't return anything. You're basically missing the last bit of the implementation: once you look up the appropriate function by name, you need to call that function and return the result.
def key_check(self, key): # "x" is a meaningless name; use something meaningful
lookup = {
'grade': self.grade
}
func = lookup[key] # Look up the correct method
return func() # Call that method and return its result
Technically you could in-line all that into one statement if you really wanted to, but unless performance is at a premium I wouldn't recommend it as the readability suffers.

Scala way / idiom of dealing with immutable List

I have found successes using ideas of immutable List but I am stumped when come to this piece of code here. I find myself has written something more Java than of Scala style. I would prefer to use List(...) instead of Buffer(...) but I don't see how I can pass the same modified immutable List to the next function. guesses is also modified within eliminate(...).
Any suggestions to help me to make this the Scala way of doing this is appreciated. Thanks
val randomGuesses = List(...) // some long list of random integers
val guesses = randomGuesses.zipWithIndex.toBuffer
for ( s <- loop()) {
val results = alphaSearch(guesses)
if (results.size == 1) {
guesses(resultes.head._2) = results.head._1
eliminate(guesses, resultes.head._2)
}
else {
val results = betaSearch(guesses)
if (results.size == 1) {
guesses(resultes.head._2) = results.head._1
eliminate(guesses, resultes.head._2)
} else {
val results = betaSearch(guesses)
if (results.size == 1) {
guesses(resultes.head._2) = results.head._1
eliminate(guesses, resultes.head._2)
}
}
}
}
Here are some general tips since this might be better suited for codereview and the code posted is incomplete with no samples.
You can use pattern matching instead of if and else for checking the size.
results.size match{
case 1 => ... //Code in the if block
case _ => ... //Code in the else block
}
Instead of mutating guesses create a new List.
val newGuesses = ...
Then pass newGuesses into eliminate.
Lastly, it looks like eliminate modifies guesses. Change this to return a new list. e.g.
def eliminate(list: List[Int]) = {
//Eliminate something from list and return a new `List`
}