I have this code in Groovy:
def list1 = [[objid:1, name:"One"], [objid:2, name:"Two"]];
def list2 = [[objid:2, name:"Hello"]];
def list3 = list1 - list2;
println list3;
The output of the code above will result something like this:
[[objid:1, name:One], [objid:2, name:Two]]
QUESTION: How to subtract List by objid? I want the result to be something like this: [[objid:1, name:One]] since objid:2 is present in the List1. How to code it?
Given
list1 = [[objid:1, name:"One"], [objid:2, name:"Two"]]
list2 = [[objid:2, name:"Hello"]]
In order to get list1 entries with entries matching objids from list2 filtered out, collect the ids that need to be subtracted into a set, then construct a predicate that tests that the id of the given object isn't in that set:
ids = list2.collect { it['objid'] } as Set
list3 = list1.findAll { !ids.contains(it['objid']) }
(Using a set instead of a list should make the lookups faster.)
The result is that list3 contains:
[[objid:1, name:One]]
You may need a function, try this:
def list1 = [[objid:1, name:"One"], [objid:2, name:"Two"]];
def list2 = [[objid:2, name:"Hello"]];
def subtract (list1, list2) {
def retlist = [];
if (list1 == null || list2 == null) {
return null;
}
for(test1 in list1) {
def exists = false;
for (test2 in list2) {
exists = (test1.objid == test2.objid) || exists;
}
if (!exists) {
retlist.push(test1);
}
}
return retlist;
}
def list3 = subtract(list1 ,list2);
println list3;
You'll want a function that does the following:
class Foo
{
public String Name;
public Integer Id;
}
public Foo getObjId(int id) {
for (Foo foo : list) {
if (foo.getId() == id) {
return foo; // foo bar!
}
}
return null; // foo bar not found.
}
Related
I'm writing a test using the Spock framework and I found a strange bavior when testing equality of lists.
When I compare two lists like
sourceList == targetList
and those lists contains Comparable objects of the same type, those objects are tested for equality using its compareTo methods instead of equals.
Is there any simple way how to force Groovy to use equals when testing equality on such lists?
Here is a simple test specification where the test should fail, but it does not.
class Test extends Specification {
def "list test"() {
when:
def listA = [[index: 1, text: "1"] as Bean, [index: 2, text: "2"] as Bean]
def listB = [[index: 1, text: "1"] as Bean, [index: 2, text: "3"] as Bean]
then:
listA == listB
}
class Bean implements Comparable<Bean> {
int index
String text
#Override
public int compareTo(Bean o) {
return index.compareTo(o.index);
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + index;
result = prime * result + ((text == null) ? 0 : text.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Bean)) {
return false;
}
Bean other = (Bean) obj;
if (index != other.index) {
return false;
}
if (text == null) {
if (other.text != null) {
return false;
}
} else if (!text.equals(other.text)) {
return false;
}
return true;
}
}
}
Asking for a simple method is subjective. The key to this answer is that, in Groovy, the is() method will check object equality.
Consider this new method on ArrayList. If appropriate, it will zip together the two lists and call is() on each pair of items.
ArrayList.metaClass.myCompare = { listB ->
def result = false
def listA = delegate
if (listB && listA.size() == listB.size()) {
def zipped = [listA, listB].transpose()
result = zipped.inject(true){ ok, pair ->
ok && pair[0].is(pair[1])
}
}
result
}
then:
def beanA = new Bean(index: 1, text: 'a')
def beanA1 = new Bean(index: 1, text: 'a')
def beanB = new Bean(index: 2, text: 'b')
assert [beanA, beanB].myCompare([beanA, beanB])
assert ! [beanA, beanB].myCompare([beanA1, beanB])
assert ! [beanA, beanB].myCompare([beanA])
assert ! [beanA, beanB].myCompare(null)
assert ! [beanA, beanB].myCompare([])
In groovy, "==" is replaced with equals if items are not comparable, or with compareTo if they implement Comparable. I do not know a simple way to force equals, if the collections have no duplicates, you can check the elements of the collection one by one:
def collectionsEqual (Collection<?> collection1, Collection<?> collection2) {
if (collection1.size() != collection2.size()) {
return false
}
for (elem1 in collection1) {
def founded = false;
for (elem2 in collection2) {
if (elem1?.equals (elem2)) {
founded = true
}
}
if (!founded) {
return false
}
}
true
}
but, in https://www.baeldung.com/java-compareto we have:
It is also strongly recommended, though not required, to keep the
compareTo implementation consistent with the equals method
implementation:
x.compareTo(y) == 0 should have the same boolean value as x.equals(y)
This will ensure that we can safely use objects in sorted sets and
sorted maps.
In groovy the original value get overwritten when I change values in a clone list. Does anyone know if I am doing it wrong or it is a bug older groovy?
I am doing something like this:
List<Foo> myFooList = fooList.newFoos.findAll { it.type == "Types}
List<Foo> newFoo = fooList.oldFoos.findAll { it.type == "Types}.clone()
newFoo.each {
it.value = "neeeew value"
}
Foo fooOne = newFoo.each { foooo ->
fooTwo = fooList.oldFoos.find { it.id == foooo.id}
if(fooTwo.value != foooo.value) {
//Here it should go... but it turns out that fooTwo.value == foooo.value
}
}
the clone method called on list produces a new list but with the same objects in it.
you want to build new list with new objects. here is an example:
#groovy.transform.ToString
class Foo{
String type
String value
}
def fooList = [
new Foo(type:"Types", value:'old value1'),
new Foo(type:"Not", value:'old value2'),
new Foo(type:"Types", value:'old value3'),
new Foo(type:"Not", value:'old value4'),
]
def newFooList = fooList.
findAll{it.type=='Types'}.
collect{ new Foo(type:it.type, value:"new value") } //build new array with transformed elements
//check the original list
fooList.each{assert it.value!='new value'}
//check new list
newFooList.each{assert it.value=='new value'}
assert newFooList.size()==2
println fooList
println newFooList
I solved the issue by adding clone of the element as well, any way it became to much of cowboy fix:
List<Foo> myFooList = fooList.newFoos.findAll { it.type == "Types}
List<Foo> newFoo = fooList.oldFoos.findAll { it.type == "Types}.collect {it.clone()}
newFoo.each {
it.value = "neeeew value"
}
Foo fooOne = newFoo.each { foooo ->
fooTwo = fooList.oldFoos.find { it.id == foooo.id}
if(fooTwo.value != foooo.value) {
//Here it should go... but it turns out that fooTwo.value == foooo.value
}
}
I have an action which I need to do over an object several times and the collect the result of each action with that object.
Basically it looks like this
def one_action = { obj ->
def eval_object = process(obj)
eval_object.processed = true
return eval_object
}
def multiple_actions = { obj, n, action ->
def result = []
n.times {
result << action(obj)
}
return result
}
println multiple_actions(object, 10, one_action)
Is there a way to omit declaration of def result = [] and return the list directly from the closure?
You can collect the range, starting from zero:
def one_action = { obj ->
"a $obj"
}
def multiple_actions = { obj, n, action ->
(0..<n).collect { action obj }
}
assert multiple_actions("b", 3, one_action) == ["a b"] * 3
Let's say that I have a collection of parameters
def params = ['a','b','c']
Is there a short way to run a method that accepts a single parameter once for every element of a collection to replace this:
params.each {
foo(it)
}
with something more declarative (like a "reverse" spread operator)?
You can use collect:
def params = ['a','b','c']
def foo(param) {
'foo-' + param
}
assert ['foo-a', 'foo-b', 'foo-c'] == params.collect { foo(it) }
Or just a closure
def foo = { a -> a + 2 }
def modified = list.collect foo
You can use method pointer:
def l = [1,2,3]
l.each(new A().&lol)
class A {
def lol(l) {
println l
}
}
Or add a method that will do the task you need:
def l = [1,2,3]
List.metaClass.all = { c ->
delegate.collect(c)
}
l.all(new A().&lol)
class A {
def lol(l) {
println l
return l+2
}
}
As I am reading values from a file in my Groovy code, I want to assign these values to the equivalent properties in my object as i am iterating through the map values!
code:
new ConfigSlurper().parse(new File(configManager.config.myFile.filepath)
.toURI().toURL()).each { k,v ->
if (k == 'something') {
v.each {
myObject.$it =v.$it
// so here i want this dynamic assignment to occur
}
}
}
You code there would already work like this, if you would use the form:
myObject."$it.key" = it.value
Here is a slightly more protective version:
class MyObject {
Long x,y
}
def obj = new MyObject()
def cfg = new ConfigSlurper().parse('''\
a {
x = 42
y = 666
}
b {
x = 93
y = 23
}''')
cfg.b.findAll{ obj.hasProperty(it.key) }.each{
obj.setProperty(it.key,it.value)
}
assert obj.x==93 && obj.y==23