Nested closure resolution different between methods and properties? - groovy

When a closure's resolveStrategy is set to DELEGATE_ONLY or DELEGATE_FIRST, resolution is different in nested closures between methods and properties of the delegate. For example, in the following, x resolves to f's delegate (what I expect), but keySet() resolves to g's delegate.
​def g = {->
def f = {
{-> [x, keySet()]}()
}
f.resolveStrategy = Closure.DELEGATE_ONLY
f.delegate = [x: 1, f: 0]
f()
}
g.delegate = [x: 0, g: 0]
g()
​
Result: [1, ['x', 'g']]
Whereas without the nested closure
def g = {->
def f = {
[x, keySet()]
}
f.resolveStrategy = Closure.DELEGATE_ONLY
f.delegate = [x: 1, f: 0]
f()
}
g.delegate = [x: 0, g: 0]
g()
Result: [1, ['x', 'f']]
Is this behavior expected and documented somewhere? Is it a bug?

I believe it is a bug. If you change the map for a Expando it behaviors differently:
f = {
g = {
{ -> keySet() }()
}
g.delegate = new Expando(a: 1000, b: 900, c: 800, keySet: { 'g keyset' })
g.resolveStrategy = Closure.DELEGATE_ONLY
g()
}
f.delegate = new Expando(a: 90, x: 9, y: 1, keySet: { 'f keyset' })
assert f() == 'g keyset'
f = {
g = {
{ -> keySet() }()
}
g.delegate = [a: 1000, b: 900, c: 800]
g.resolveStrategy = Closure.DELEGATE_ONLY
g()
}
f.delegate = [a: 90, x: 9, y: 1]
assert f().toList() == ['a', 'b', 'c'] // fails :-(
Maybe filling a JIRA?

I discovered a workaround if you never want to fall through to the owner (ie, DELEGATE_ONLY): you can set both the delegate and the owner to the same value:
def g = {->
def f = {
{-> [x, keySet()]}()
}
def d = [x: 1, f: 0]
f = f.rehydrate(d, d, f.thisObject)
f()
}
g.delegate = [x: 0, g: 0]
g()
Result: [1, ["x", "f"]]
Note that f.owner = d does not work: while there is no error, it seems to be a no-op. You must use rehydrate.

Related

recursive function for compare two tuples and return one tuple with no repetitions

I've tried everything, but I can't make this function work at all. At least not the way I want.
def uniao(x, y):
a = list(x)
b = list(y)
i = len(a)-1
j = len(b)-1
if a == b:
return tuple(a) + tuple(b)
else:
if b[j] != a[i]:
a.append(b[j])
return uniao(a, b)
else:
return tuple(a)
print(uniao((1, 2, 3), (2, 4, 5)))
This is where I approached the result, but it should be '12345'.
Does this rewrite of your function do what you want:
def uniao(x, y):
if not y:
return x
head, *tail = y
if head not in x:
x += (head,)
return uniao(x, tail)
print(uniao((1, 2, 3), (2, 4, 5)))
Or are there more rules to this puzzle?

Switch values in two multi-nested maps in groovy

I am writing a method in order to replace values in one of two maps depending on if the keys match together. For example lets say we have two maps:
def oldmap = [emails: 1, files:[permissions: 3, config:4]]
def replacementmap = [emails: 2, permissions: 5]
// I want this old map to have updated values for keys that match after the method is called.
replacementPermissions(oldmap, replacementmap)
print oldmap
//prints [emails: 2, files:[permissions: 5, config:4]]
I have written this method shown below that works for one layered nested map, but I noticed a recursive solution would be a better option instead because my solution wouldn't work for multi-layered nested maps.
def replacePermissions(read, params){
read.each{x,y ->
temp = x
if (y instanceof Map){
y.each{x2,y2->
temp = x2
params.each{xx,yy->
if (temp == xx) y.put(x2, yy)
if (yy instanceof Map){
yy.each{aa, bb->
if (temp == aa) y.put(x2, bb)
}
}
}
}
}
else{
params.each{x1,y1->
if (temp == x1) read.put(x, y1)
}
}
}
return read
}
I am having trouble wrapping my head around how to think of a recursive solution for traversing and matching keys to swap values.
Right now I have this with
No signature of method: main.swapsearch() is applicable for argument types: (java.util.LinkedHashMap, java.lang.Integer) values: [[lol3:[lol5:4, lol6:10], lol4:4], 5]
Possible solutions: swapsearch(java.util.Map, java.util.Map)
def swapsearch(Map mapa, Map mapb){
mapa.each{x,y ->
temp = x
mapb.each{x1, y1->
if (y instanceof Map || y1 instanceof Map){
swapsearch(y, y1)
}
else if (temp == x1){
mapb.put(x, y1)
}
}
}
mapb
}
Map oldmap = [lol1: 1, lol2:[lol3: [lol5: 4, lol6: 10], lol4:4]]
Map newmap = [lol1: 5, lol5: 111]
print newmap
newmap = swapsearch(oldmap, newmap)
print newmap
SOLUTION with help of #injecteer:
I was able to do a simple recursion as so:
// Make sure repl map is flattened
def switchMaps( Map src, Map repl ){
src.each{key,value ->
if( repl.containsKey(key) ){
src.put(key, repl[key])
}
else if( value && value instanceof Map ){
replacemaps (value, repl)
}
}
src
}
Some simple recursion:
Map oldmap = [emails: 1, files:[permissions: 3, config:4, deep:[ deeper:[ verydeep:1 ] ] ] ]
Map replacementmap = [emails: 2, permissions: 5, verydeep:400]
def replace( Map src, Map repl ){
src.each{
if( repl.containsKey( it.key ) )
it.value = repl[ it.key ]
else if( it.value && Map.isAssignableFrom( it.value.getClass() ) )
replace it.value, repl
}
}
replace oldmap, replacementmap
assert oldmap.emails == replacementmap.emails
assert oldmap.files.permissions == replacementmap.permissions
assert oldmap.files.deep.deeper.verydeep == replacementmap.verydeep
If your replacementmap is also nested, you have to pre-process it before using, like so:
Map replacementmap = [emails: 2, permissions: 5, deep:[ config:300, toodeep:[ verydeep:400 ] ] ]
Map flatten( Map m, Map res = [:] ) {
m.each{ k, v ->
if( !v ) return
if( Map.isAssignableFrom( v.getClass() ) ) flatten v, res
else res[ k ] = v
}
res
}
Map flatRepl = flatten replacementmap
assert flatRepl == [emails:2, permissions:5, config:300, verydeep:400]

Householder Reflection of a vector

I want to construct a Householder reflection of a vector. My attempt is below according to the algorithm.
import math
import numpy as np
def vector_norm(n , vec):
result = 0
for k in range (n ):
result = result + vec[k] * vec[k]
return math.sqrt(result)
def householder(vec):
#vec the vector to be transformed
vec = np.asarray(vec, dtype=float)
if vec.ndim != 1:
raise ValueError("vec.ndim = %s, expected 1" % vec.ndim)
n = len(vec)
I = np.eye(n)
e1 = np.asarray(([0.0]*n),dtype=float)
e1[0] = 1.0
V1 = vec - vector_norm(n , vec)*e1
V_trans = np.array([V1])
H = I - 2 * ((V_trans.T # V_trans) / vector_norm( n ,V1))
return V1 , H
However, when I check;
v = np.array([1, 2, 3])
v1, h = householder(v)
assert_allclose(np.dot(h, v1), v)
assert_allclose(np.dot(h, v), v1)
The result is wrong.
AssertionError:
Not equal to tolerance rtol=1e-07, atol=0
(mismatch 100.0%)
x: array([ 22.095208, -16.118139, -24.177209])
y: array([1, 2, 3])

How can i filter a List neighbors is equal? Request something like unique()

If have list of af string, how can filter so equal neighbors only appears one?
Example:
['0.1', '0.1', '0.2','0.3','0.3','0.1','0.2']
should result in
['0.1', '0.2','0.3','0.1','0.2']
notice that element 0, 1 only appears once and element 4 and 5 also appears only once.
If use unique:
['0.1', '0.1', '0.2','0.3','0.3','0.1','0.2'].unique()
the result will be:
['0.1', '0.2','0.3'] //what is not wanted
Any suggestions for the best groovy method?
One simple option is to iterate with a trailing value:
def example = ['0.1', '0.1', '0.2','0.3','0.3','0.1','0.2']
def array = []
def trailing = -999
example.each { item ->
if (item != trailing) { array << item }
trailing = item
}
assert ['0.1','0.2','0.3','0.1','0.2'] == array
So if you want remove duplicated neighbors, you should get next item from current loop. i come up something like this:
def example = ['0.1', '0.1', '0.2','0.3','0.3','0.1','0.2']
def array = []
example.eachWithIndex { item, index ->
def next = index < example.size() - 1 ? example[ index + 1 ] : null
if(next != item) {
array.push(item)
}
}
println array ​
Another, more functional way, is as follows, using inject (known in other languages as reduce):
def example = ['0.1','0.1','0.2','0.3','0.3','0.1','0.2']
def array = example.inject([example[0]]) { acc, val ->
if (val != acc[-1]) { acc << val }
acc
}
assert ['0.1','0.2','0.3','0.1','0.2'] == array
The key is to start with array containing the first element, [example[0]], and then iterate over example. inject provides both the running accumulation and the value. If we add a log line:
def array = example.inject([example[0]]) { acc, val ->
println "acc: ${acc} val: ${val}"
if (val != acc[-1]) { acc << val }
acc
}
then output is:
acc: [0.1] val: 0.1
acc: [0.1] val: 0.1
acc: [0.1] val: 0.2
acc: [0.1, 0.2] val: 0.3
acc: [0.1, 0.2, 0.3] val: 0.3
acc: [0.1, 0.2, 0.3] val: 0.1
acc: [0.1, 0.2, 0.3, 0.1] val: 0.2

Iterate two vectors with different lengths

I have two Vecs that can be of different lengths, for example:
let xs = vec![1, 2, 3, 4, 5];
let ys = vec![11, 12, 13];
I want to iterate over them in pairs, printing:
x=1, y=11
x=2, y=12
x=3, y=13
x=4; no matching Y
x=5; no matching Y
I can use Iterator::zip to get the pairs with matching elements in both xs and ys:
for (x, y) in xs.iter().zip(ys.iter()) {
println!("x={}, y={}", x, y);
}
but for the "no matching" bits I need complex code that checks the length and takes a slice of the rest.
I wanted a solution that's fully iterator-based, so I tried:
let mut it_xs = xs.iter();
let mut it_ys = ys.iter();
while let (Some(x), Some(y)) = (it_xs.next(), it_ys.next()) {
println!("x={}, y={}", x, y);
}
while let Some(x) = it_xs.next() {
println!("x={}, no matching Y", x);
}
while let Some(y) = it_ys.next() {
println!("y={}, no matching X", y);
}
which does not work correctly, as the first loop skips the first element that doesn't have a match in the other list (x=4).
Is it possible to solve with the help of an iterator without slicing the rest of the larger Vec?
The implementation without external crates:
let mut it_xs = xs.iter();
let mut it_ys = ys.iter();
loop {
match (it_xs.next(), it_ys.next()) {
(Some(x), Some(y)) => println!("x={}, y={}", x, y),
(Some(x), None) => println!("x={}, no matching Y", x),
(None, Some(y)) => println!("y={}, no matching X", y),
(None, None) => break,
}
}
itertools has a method zip_longest that does just that:
use itertools::Itertools;
use itertools::EitherOrBoth::{Both, Left, Right};
for it in xs.iter().zip_longest(ys.iter()) {
match it {
Both(x, y) => println!("x={}, y={}", x, y),
Left(x) => println!("x={}, no matching Y", x),
Right(y) => println!("y={}, no matching X", y),
}
}

Resources