Filter map key length in Groovy - groovy

I am trying to create a new map, extracting from another map the keys and trying to insert the ones that are less than 13 characters long. I have tried to filter like this but it is impossible for me.
Map<String, String> maps = entriesOnlyOnLeft.findAll { it.key }.each { it.key.length() < 13 }
Output:
log.info("Key Map ---> "+maps.keySet())
[431486899900600, 280799200020001, 251206899900600, 080196899900604, 350166899900600, 180876899900600, 260896899900600, 372746899900600, 442166899900600, 330446899900600, 401946899900600, 110126899900600, 200696899900600, 410916899900600, 060156899900600, 210416899900600, 040136899900600, 290676899900600, 140216899900600, 020036899900600, 360386899900600, 312016899900600, 280796800220073, 451686899900600, 150306899900600, 280796800110071, 280796899900604, 320546899900600, 492756899900600, 240896899900600, 380386899900600, 000000E04921301, 100376899900600, 480206899900600, 000000E00004101, 280796800330051, 280796800330064, 050196899900600, 170796899900600, 390756899900600, 520016899900600, 000000E04921701, 280796899900075, 280796899900074, 280796899900077, 280796899900076, 280796899900079, 280796899900078, 280796899900065, 280796899900053, 280796899900057, 280796899900040, 280796899900041, 280796899900046, 280796899900045, 280796899900048, 280796899900049, 191306899900600, 030146899900600, 280796899900032, 280796899900035, 280796899900034, 280796899900036, 280796899900039, 280796899900038, 280796800440072, 341206899900600, 160786899900600, 130346899900600, 120406899900600, 510016899900600, 502976899900600, 471866899900600, 270286899900600, 300306899900600, 090596899900600, 000000E04924801, 230506899900600, 462506899900600, 070406899900600]

You almost had it. Here's the solution:
Map<String,String> results = entriesOnlyOnLeft.findAll { it.key.length() < 13 }
The closure used in findAll must return a truthy result in order for it to include that Map.Entry in the results. Also the findAll closure will be invoked for each item in the given Map (ie entriesOnlyOnLeft) so there is no need for a call to each. Plus each returns void so there wouldn't be any results returned to the caller by call each.

You can try the following way (Somewhat mutating way)
Map<String, String> maps = new HashMap<>();
entriesOnlyOnLeft.each { it ->
if (it.key.length() < 13) {
maps.put(it.key, it.value)
}
}

Related

Method return wrong type of value in Groovy

I'm working on a groovy method to look for a custom attribute and return the value if the key is found.
The problem is that the method is returning the type of value instead of the value.
// There is more code before, but its not involved with this issue.
def UUIDca = 'UUID'
String customAttributeValue = grabCustomAttribute(UUIDca, event_work)
appendLogfile("\n\nTest grabCustomAttribute: ${customAttributeValue}\n")
}
// Grab the Custom Message Attribute values by name
String grabCustomAttribute (String findElement, OprEvent event){
appendLogfile("""\nIN grabCustomAttribute\nElement to look: ${findElement}\n""")
def firstItem = true
if (event.customAttributes?.customAttributes?.size()) {
event.customAttributes.customAttributes.each { ca ->
// Define each CMA to catch here
appendLogfile("""\nElement: ${ca.name} - """)
appendLogfile("""Valor: ${ca.value}\n""")
if ("${ca.name}" == findElement) {
String customValue = ca.value
appendLogfile("""Custom Attribute Found\n""")
appendLogfile(customValue)
return customValue
}
}
}
}
appendLogfile is basically a print to a log file :)
This is the output I'm getting.
IN grabCustomAttribute Element to look: UUID
Element: UUID - Valor: c3bb9169-0ca3-4bcf-beb1-f94eda8ebf1a
Custom Attribute Found
c3bb9169-0ca3-4bcf-beb1-f94eda8ebf1a
Test grabCustomAttribute: [com.hp.opr.api.ws.model.event.OprCustomAttribute#940e503a]
Instead of returning the value, it returns the type of object. It's correct, but I'm looking for the value.
I believe the solution is really simple, but I'm very new to Groovy.
Any help will be appreciated.
Thanks.
In this case the return statement is for the closure, not for the method, so your method is actually returning the list that "each" is iterating over
The easiest approach you can take here is to use Groovy find method to find the element you are searching for. Something like this:
String grabCustomAttribute (String findElement, OprEvent event) {
return event.customAttributes.customAttributes?.find { ca -> ca.name == findElement }.value
}

Using find{ } on a map where the whole map is evaluated not each element

I created some mixin methods. Code and example below:
URL.metaClass.withCreds = { u, p ->
delegate.openConnection().tap {
setRequestProperty('Authorization', "Basic ${(u + ':' + p).bytes.encodeBase64()}")
}
}
URLConnection.metaClass.fetchJson = {
delegate.setRequestProperty('Accept', 'application/json')
delegate.connect()
def code = delegate.responseCode
def result = new JsonSlurper().parse(code >= 400 ? delegate.errorStream : delegate.inputStream as InputStream)
[
ok : code in (200..299),
body: result,
code: code
]
}
example usage:
new URL("$baseUrl/projects/$name").withCreds(u, p).fetchJson().find {
it.ok
}?.tap{
it.repos = getRepos(it.key).collectEntries { [(it.slug): it] }
}
}
When I dont use find(), my object is, as expected, a map with those 3 elements. When I use find it is a Map.Entry with key ok and value true
which produces this error:
groovy.lang.MissingPropertyException: No such property: ok for class: java.util.LinkedHashMap$Entry
Possible solutions: key
It occured to me when I wrote this post that it was treated the map as an iterable and thus looking at every entry which I have subsequently verified. How do I find on the whole map? I want it.ok because if it's true, I need to carry it forward
There is no such method in Groovy SDK. Map.find() runs over an entry set of the map you call method on. Based on expectation you have defined I'm guessing you are looking for a function that tests map with a given predicate and returns the map if it matches the predicate. You may add a function that does to through Map.metaClass (since you already add methods to URL and URLConnection classes). Consider following example:
Map.metaClass.continueIf = { Closure<Boolean> predicate ->
predicate(delegate) ? delegate : null
}
def map = [
ok : true,
body: '{"message": "ok"}',
code: 200
]
map.continueIf { it.ok }?.tap {
it.repos = "something"
}
println map
In this example we introduced a new method Map.continueIf(predicate) that tests if map matches given predicate and returns a null otherwise. Running above example produces following output:
[ok:true, body:{"message": "ok"}, code:200, repos:something]
If predicate is not met, map does not get modified.
Alternatively, for more strict design, you could make fetchJson() method returning an object with corresponding onSuccess() and onError() methods so you can express more clearly that you add repos when you get a successful response and optionally you create an error response otherwise.
I hope it helps.

Compare two maps and find differences using Groovy or Java

I would like to find difference in two maps and create a new csv file with the difference (and put the difference between **) like below:
Map 1
[
[cuInfo:"T12",service:"3",startDate:"14-01-16 13:22",appId:"G12355"],
[cuInfo:"T13",service:"3",startDate:"12-02-16 13:00",appId:"G12356"],
[cuInfo:"T14",service:"9",startDate:"10-01-16 11:20",appId:"G12300"],
[cuInfo:"T15",service:"10",startDate:"26-02-16 10:20",appId:"G12999"]
]
Map 2
[
[name:"Apple", cuInfo:"T12",service:"3",startDate:"14-02-16 10:00",appId:"G12351"],
[name:"Apple",cuInfo:"T13",service:"3",startDate:"14-01-16 13:00",appId:"G12352"],
[name:"Apple",cuInfo:"T16",service:"3",startDate:"14-01-16 13:00",appId:"G12353"],
[name:"Google",cuInfo:"T14",service:"9",startDate:"10-01-16 11:20",appId:"G12301"],
[name:"Microsoft",cuInfo:"T15",service:"10",startDate:"26-02-16 10:20",appId:"G12999"],
[name:"Microsoft",cuInfo:"T18",service:"10",startDate:"26-02-16 10:20",appId:"G12999"]
]
How can I get the output csv like below
Map 1 data | Map 2 data
service 3;name Apple;
cuInfo;startDate;appId | cuInfo;startDate;appId
T12;*14-02-16 10:00*;*G12351* | T12;*14-01-16 13:22*;*G12355*
T13;*14-01-16 13:00*;*G12352* | T13;*12-02-16 13:00*;*G12356*
service 9;name Google;
T14;*10-01-16 11:20*;*G12301* | T12;*10-01-16 11:20*;*G12300*
Thanks
In the following I'm assuming that the list of maps is sorted appropriately so that the comparison is fair, and that both lists are of the same length:
First, create an Iterator to traverse both lists simultaneously:
#groovy.transform.TupleConstructor
class DualIterator implements Iterator<List> {
Iterator iter1
Iterator iter2
boolean hasNext() {
iter1.hasNext() && iter2.hasNext()
}
List next() {
[iter1.next(), iter2.next()]
}
void remove() {
throw new UnsupportedOperationException()
}
}
Next, process the lists to get rows for the CSV file:
def rows = new DualIterator(list1.iterator(), list2.iterator())
.findAll { it[0] != it[1] } // Grab the non-matching lines.
.collect { // Mark the non-matching values.
(m1, m2) = it
m1.keySet().each { key ->
if(m1[key] != m2[key]) {
m1[key] = "*${m1[key]}*"
m2[key] = "*${m2[key]}*"
}
}
[m1, m2]
}.collect { // Merge the map values into a List of String arrays
[it[0].values(), it[1].values()].flatten() as String[]
}
Finally, write the header and rows out in CSV format. NOTE: I'm using a proper CSV; your example is actually invalid because the number of columns are inconsistent:
def writer = new CSVWriter(new FileWriter('blah.csv'))
writer.writeNext(['name1', 'cuInfo1', 'service1', 'startDate1', 'appId1', 'name2', 'cuInfo2', 'service2', 'startDate2', 'appId2'] as String[])
writer.writeAll(rows)
writer.close()
The output looks like this:
"name1","cuInfo1","service1","startDate1","appId1","name2","cuInfo2","service2","startDate2","appId2"
"Apple","T12","3","*14-02-16 10:00*","*G12351*","Apple","T12","3","*14-01-16 13:22*","*G12355*"
"Apple","T13","3","*14-01-16 13:00*","*G12352*","Apple","T13","3","*12-02-16 13:00*","*G12356*"
"Google","T14","9","10-01-16 11:20","*G12301*","Google","T14","9","10-01-16 11:20","*G12300*"

ServiceStack.Text: Use Linq and the ConvertAll

Iam using the ServiceStack.Text JsonObject parser to map into my domain model. I basically have anthing working, except when using Linq to filter on ArrayObject and the try to convert it using convertAll. Iam cannot come arround actuall after using link, adding element by element to an JsonArrayObjects list and then pass it.
var tmpList = x.Object("references").ArrayObjects("image").Where(y => y.Get<int>("type") != 1).ToList();
JsonArrayObjects tmpStorage = new JsonArrayObjects();
foreach (var pic in tmpList) {
tmpStorage.Add(pic);
}
if (tmpStorage.Count > 0) {
GalleryPictures = tmpStorage.ConvertAll(RestJsonToModelMapper.jsonToImage);
}
Question:
Is there a more elegant way to get from IEnumarable back to JsonArrayObjects?
Casting will not work, since where copys elements into a list, instead of manipulating the old one, therefor the result is not an downcasted JsonArrayObjects, rather a new List object.
Best
Considering this more elegant is arguable, but I would probably do:
var tmpStorage = new JsonArrayObjects();
tmpList.ForEach(pic => tmpStorage.Add(RestJsonToModelMapper.jsonToImage(pic)));
And if this kind of conversion is used frequently, you may create an extension method:
public static JsonArrayObjects ToJsonArrayObjects(this IEnumerable<JsonObject> pics)
{
var tmpStorage = new JsonArrayObjects();
foreach(var pic in pics)
{
tmpStorage.Add(RestJsonToModelMapper.jsonToImage(pic));
}
return tmpStorage;
}
This way you would end up with simpler consumer code:
var tmpStorage = x.Object("references")
.ArrayObjects("image")
.Where(y => y.Get<int>("type") != 1)
.ToJsonArrayObjects();
Like this?
var pictures = x.Object("references")
.ArrayObjects("image")
.Where(y => y.Get<int>("type") != 1)
.Select(RestJsonToModelMapper.JsonToImage)
.ToList();

How i can get latest record by using FirstOrDefault() method

Suppose i have 2 records in data base
1) 2007-12-10 10:35:31.000
2) 2008-12-10 10:35:31.000
FirstOrDefault() method will give me the first record match in sequence like 2007-12-10 10:35:31.000 but i need the latest one which is 2008-12-10 10:35:31.000
if ((from value in _names where value != null select value.ExpiryDate < now).Any())
{
return _names.FirstOrDefault();
}
You can use:
return _names.LastOrDefault();
However, your if just sends another unnecessary query (and it is a wrong query too). If you don't have any record, LastOrDefault and FirstOrDefault will return null. You can use something like this to improve the code:
var name = _names.LastOrDefault();
if(name != null)
{
return name;
}
// other code here
If you really want to use FirstOrDefault, you should order descending, like:
var name = _names.Where(n => n.ExpiryDate < now).OrderByDescending(n => n.ExpiryDate).FirstOrDefault();

Resources