Groovy :: Map Find Recursive - recursion

Edit
See #tim's solution below for the "correct" Groovy-esque approach to map recursion. Since Map findRecursive does not yet exist in Groovy, if you find yourself needing this functionality in various parts of your app, just add it to Map metaClass:
Map.metaClass.findRecursive = {String key->
if(delegate.containsKey(key)) return delegate."$key"
else
for(m in delegate) {
if(m.value in Map) return m.value.findRecursive(key)
}
}
// then anywhere in your app
someMap.findRecursive('foo')
Original
Was hoping something like findResult{it.key=='foo'} would recurse through map elements beyond 1-d deep, but appears not to be the case.
Rolled my own recursive map finder, but am wondering if there's a better way to do this. Maybe there's a built-in function I'm missing, or an even Groovier (concise) way to pull off the below:
Map map = [school:[id:'schoolID', table:'_school',
children:[team:[id:'teamID',table:'_team',
children:[player:[id:'playerID',table:'_roster']]
]]
]]
class Foo {
static finder = {Map map, String key->
if(map.containsKey(key)) return map[key]
else
for(m in map) {
if(m.value in Map) return this.finder(m.value,key)
}
}
}
println Foo.finder(map,'team')

With Groovy 1.8 (reqd for the findResult method), you could do something like this:
class DeepFinder {
static Object findDeep( Map map, Object key ) {
map.get( key ) ?: map.findResult { k, v -> if( v in Map ) v.findDeep( key ) }
}
}
use( DeepFinder ) {
println map.findDeep( 'team' )
}
There's no recursing default Groovy method that I know of...

Related

How can I get out of this infinite loop?

I am writing a recursive function to find the index of a node in a linked list. It looks like this:
function indexAt(node, collection, linkedList) {
let index = 0;
if (node === nodeAt(index, linkedList,collection)) {
return index
} else {
index ++
return indexAt(node, collection, linkedList)
}
}
It calls on the nodeAt function, which looks like this:
function nodeAt(index, linkedList, collection) {
let node = collection[linkedList];
for (let i=0; i < index; i++) {
node = next(node, collection)
}
return node
}
This works fine when the index is 0, but when it is anything else, it increments the index, then sets it back to 0, entering an infinite loop. How can I fix this without fundamentally altering the code?
Well at the start of the function you reset the index to 0. So every time it recurs, it resets the index, thus causing your infinite loop.
An easy fix is to declare the index variable outside the function. That will ensure it's not reset every time the function recurs.
A better fix would be to pass the index as an argument to the function so that it will always keep track of its own index.
Just make a helper that holds the extra variable:
function indexAt(node, collection, linkedList) {
function indexAt(index, node, collection, linkedList) {
if (node === nodeAt(index, linkedList, collection)) {
return index
} else {
return indexAt(index + 1, node, collection, linkedList)
}
}
return indexAt(0, node, collection, linkedList);
}
Now you count from 0...n and make nodeAt start at the beginning each time making this O(n^2). A much better way would be that the helper has the current node, initialized at collection[linkedList] and stepping with next(currentNode) and index + 1 until node === currentNode. That would be a O(n) solution. indexAt doesn't really need to be recursive unless it is a requirement.

Is there a way to filter out null Any? values in Kotlin Map?

I'm trying to think of a function that would allow a Map<String, Any?> object to be treated as Map<String,Any> through type inference through applying a single function.
I am pretty new to the transformation functions in Kotlin and have tried the various filter and filterValues filterNot on the map like so:
val input = mapOf(Pair("first",null))
val filtered: Map<String,Any> = input.filter { it.value!=null }
it also fails to compile with any of these
input.filterValues { it!=null }
input.filterNot { it.value==null }
input.filterNot { it.value is Nothing }
The closest I can seem to get is applying multiple steps or having an Unchecked cast warning. I would have thought that filtering the values to be !=null would suffice. My only other thought is that it's due to the generics?
The filter functions return a Map with the same generic types as the original map. To transform the type of the value, you need to map the values from Any? to Any, by doing a cast. The compiler can't know that the predicate you pass to filter() makes sure all the values of the filtered map are non-null, so it can't use type inference. So your best et is to use
val filtered: Map<String, Any> = map.filterValues { it != null }.mapValues { it -> it.value as Any }
or to define a function doing the filtering and the transformation in a single pass, and thus be able to use smart casts:
fun filterNotNullValues(map: Map<String, Any?>): Map<String, Any> {
val result = LinkedHashMap<String, Any>()
for ((key, value) in map) {
if (value != null) result[key] = value
}
return result
}
The compiler just doesn't perform type analysis deep enough to infer that, for example, input.filterValues { it != null } filters out null values from the map and thus the resulting map should have a not-null value type. Basically there can be arbitrary predicate with arbitrary meaning in terms of types and nullability.
There is no special case function for filtering null values out of a map in the stdlib (like there is .filterIsInstance<T>() for iterables). Therefore your easiest solution is to apply an unchecked cast thus telling the compiler that you are sure about the type safety not being violated:
#Suppress("UNCHECKED_CAST")
fun <K, V> Map<K, V?>.filterNotNullValues() = filterValues { it != null } as Map<K, V>
See also: another question with a similar problem about is-check.
This yields no warnings kotlin 1.5.30
listOfNotNull(
nullableString?.let { "key1" to it },
nullableString?.let { "key2" to it }
).toMap()

java8 stream style for retrieving a inner part of map through a field list?

For example, given a map like below:
{
"k1": {
"k2": {
"k3": {
"k4": "v"
}
}
}
}
and a field list ["k1","k2","k3"], I need to retrieve the part {"k4": "v"}.
Below is my java7-style code:
// Ignore the map building code.
Map map1 = new HashMap();
Map map2 = new HashMap();
Map map3 = new HashMap();
Map map4 = new HashMap();
map4.put("k4", "v");
map3.put("k3", map4);
map2.put("k2", map3);
map1.put("k1", map2);
Map map = map1;
System.out.println(map); //=> {k1={k2={k3={k4=v}}}}
// Code to be transformed to java8 style
List<String> fields = Arrays.asList("k1", "k2", "k3");
for(String field: fields) {
map = (Map) map.get(field);
}
System.out.println(map); //=> {k4=v}
Then how to transform above code to java 8 stream style?
I don’t think that there is any benefit in converting this into a functional style; the loop is fine and precisely expresses what you are doing.
But for completeness, you can do it the following way:
map = (Map)fields.stream()
.<Function>map(key -> m -> ((Map)m).get(key))
.reduce(Function.identity(), Function::andThen).apply(map);
This converts each key to a function capable of doing a map lookup of that key, then composes them to a single function that is applied to you map. Postponing the operation to that point is necessary as functions are not allowed to modify local variables.
It’s also possible to fuse the map operation with the reduce operation, which allows to omit the explicit type (<Function>):
map = (Map)fields.parallelStream()
.reduce(Function.identity(), (f, key)->f.andThen(m->((Map)m).get(key)), Function::andThen)
.apply(map);
Maybe you recognize now, that this is a task for which a simple for loop is better suited.
How about?
fields.stream().reduce(map1, (m, key) -> (Map) m.get(key), (a, b) -> a);

Recursive Function into Non-Recursive Function?

I have the following recursive Grails function:
private boolean isCyclic(TreeNode node) {
boolean cyclic = false
def myParents = this.parents
// if there are parents of this node
if (myParents.size() != 0) {
// if the new node is in the parents set of this node
if (myParents.contains(node)) {
cyclic = true
return cyclic
}
else {
// go into each parent of this node and test if new node is contained in their parents
myParents.each { parent ->
log.debug "go to parent: "+parent.name
if (cyclic) {
return cyclic
}
cyclic = parent.isCyclic(node)
}
}
}
return cyclic
}
How can I transform this function into a non-recursive function?
I think your code above is a contains method, rather than a cyclic check...
However here's a quick example of both a contains method and a cyclic check in an iterative style... Fingers crossed they're right
def contains( TreeNode node ) {
// if this node is the one we're looking for, return true
if( node == this ) {
return true
}
// A queue of nodes to work on
def parentQueue = this.parents as Queue
// A set of nodes we've seen (to avoid loops)
def seen = [ this ] as Set
// While we have nodes to look for
while( parentQueue ) {
// get the next node
def next = parentQueue.pop()
// Check if it's the one we're looking for
if( next == node ) return true
// And if not, add it's parents to the queue
// assuming we've not seen it before
if( !seen.contains( next ) ) {
next.parents.each { parentQueue.offer( it ) }
}
}
// Not found
return false
}
def isCyclic() {
// A queue of nodes to work on
def parentQueue = this.parents as Queue
// A set of nodes we've seen (to detect loops)
def seen = [ this ] as Set
// While we have nodes to look for
while( parentQueue ) {
// Look at the next element in the queue
def next = parentQueue.pop()
// If we've seen it before, it's cyclic
if( seen.contains( next ) ) return true
// Otherwise, record we've seen this node
seen << next
// And add its parents tothe queue
next.parents.each { parentQueue.offer( it ) }
}
// All done, not cyclic
return false
}
Tom Moertel wrote solution for this problem on his blog.
He clearly explained the transformation of recursive function into the iterative (link).
I have used his approach to transform my own functions when I needed and I was convinced that is correct.
I hope that helps.
Basically to transform a recursive function into an iterative function you should notice which is the case base(this case is the stop case of recursive function), put all functionality into a loop and use that base case as exit condition of used loop.
Perhaps i didn't explain it very well but every recursive function has an iterative function.

Newbie on use of recursion in Groovy/traverse tree?

In our current application we have a need to traverse down a tree and capture all operators on a specific device (and child devices). A device could have child devices with also specific operators on it.
As i am new to the use of recursion in Groovy i am wondering if i am doing things right..?
Any pointer to help me learn better ways of doing things?
def listOperators(device) {
// list with all operator id's
def results = []
// closure to traverse down the tree
def getAllOperators = { aDevice->
if(aDevice) {
aDevice.operators.each { it ->
results << it.id
}
}
if (aDevice?.children) {
aDevice.children.each { child ->
results << owner.call(child)
}
}
}
// call the closure with the given device
getAllOperators(device)
// return list with unique results
return results.unique()
}
A couple things to note:
Doing the recursive call through owner is not a good idea. The definition of owner changes if the call is nested within another closure. It's error prone and has no advantages over just using the name. When the closure is a local variable, split its up the declaration and definition of the closure so the name is in scope. E.g.:
def getAllOperators
getAllOperators = { ...
You are appending the operators to a result list outside the recursive closure. But you are also appending the result of each recursive call to the same list. Either append to the list or store the results from each recursive call, but not both.
Here's a simpler alternative:
def listOperators(device) {
def results = []
if (device) {
results += device.operators*.id
device.children?.each { child ->
results += listOperators(child)
}
}
results.unique()
}

Resources