Groovy hashmap and looping - groovy

I need to store key value pairs in groovy like for ex, store, address
key: store abc val: 123 street
key: store xyz val: north street
How can I achieve this? I tried below
mapAddress = [store:"abc", addr:"123 street"]
mapAddress.append
mapAddress = [store:"xyz", addr:"north street"]
mapAddress.append
But it retains only the last record store: xyz.
And how can I loop only the unique stores using for loop? Thanks in advance for your help.

It seems you need to create a list of maps.
See https://groovy-lang.org/groovy-dev-kit.html#_map_literals
In your example you just reassign your map with the new value

Do you really need to store them in the format you've showed?
I recommend storing them like so:
def stores = [:] // define your variable here
stores << ["abc": "123 street"] // first entry
stores << ["xyz": "north street"] // second entry
Or if you need to have more data per each store, then you can store them in a map of maps:
def stores = [:]
stores << ["abc": [address: "123 street", "some other property": "some value"]]
stores << ["xyz": [address: "north street", "some other property": "some other value"]]
Maps can only hold unique keys, so if you add a new entry with the same key as one that's already in the map, the previous entry will be replaced.
In both of the cases you can simply loop through them via
stores.each{ println(it) }.
If you plan to have multiple stores that will have the same key, you could store them in a map of lists, for example:
def stores = [:]
stores << ["abc": [[address: "123 street", "some other property": "some value"], [address: "456 street", "some other property": "some value"]]]
stores << ["xyz": [[address: "north street", "some other property": "some other value"]]]
stores.each {
println it.value.first()
}
But, at this point you're probably better off using classes to define your data.

Related

Tabulator - Sorting groups by group calcResults

Is it possible to order results of grouped items by the calculation results for each group? It seems that when I set the initialSort (or when I don't)it sorts by the order of the items within each group, rather than by the total calculation of each group.
For example, if I have data that looks something like this:
[
{id:1, company:"company 1", quantity:"10"},
{id:2, company:"company 1", quantity:"10"},
{id:3, company:"company 1", quantity:"10"},
{id:4, company:"company 2", quantity:"20"},
{id:5, company:"company 2", quantity:"1"},
{id:6, company:"company 2", quantity:"1"},
{id:7, company:"company 3", quantity:"9"},
{id:8, company:"company 3", quantity:"9"},
{id:9, company:"company 3", quantity:"9"},
]
I would end up with groups ordered:
Company 2: 22 // Highest qty 20
company 1: 30 // Highest qty 10
company 3: 27 // Highest qty 9
What I am trying to get is:
company 1: 30
company 3: 27
Company 2: 22
I can see the calculation results, but I'm not sure how to resort the groups, assuming it's possible. If anyone can point me in the right direction I will be quite grateful.
Rows can only be sorted according to a field stored in the row data.
Rows are sorted individually and then grouped, with groups appearing in the order of the sorted data.
In order to sort your table in this way, you would need to analyse your row data first before ingesting it into the table, and then set a field on each row with the desired order for the group that contains it.
The other option is to manually specify the groups you want using the groupValues option, with this approach you specify the exact groups you want and the order they should appear:
groupValues:[["male", "female", "smizmar"]]
Thanks Oli for pointing me in the direction of 'groupValues'. I ended up writing a function that uses the calcResults to get the sort order I want and then push them into groupValues to get the ordering I'm looking for.
const sortByGroupCalc = ( thisTable, thisSortField, thisSortDirection ) => {
// Temp arrays
let tempCalcArray = [];
let tempSortArray = [];
// Get calculation results
const calcResults = thisTable.getCalcResults();
// Populate Array with key:value pairs from the caculation results
for( const [key, value] of Object.entries(calcResults)) {
tempCalcArray.push([key, value.top[thisSortField]])
};
// Sort the object by value and direction and then create an array of the keys
tempCalcArray
.sort(function(a, b) {
if( thisSortDirection === 'asc' ) {
return a[1] - b[1];
} else {
return b[1] - a[1];
}})
.map(
x => tempSortArray.push(x[0])
);
// Set group order according to sort order
thisTable.setGroupValues([tempSortArray]);
}
I'm calling it in the dataSorted function. It's not perfect for all occasions, I imagine. But it seems to do what I need.
Thanks again.

U-SQL trying to Extract a list of ints from nested JSON object

I'm trying to extract the ErrorReasons, along with the State and Id from this structure
{
"id": "abcGuid",
"RegistrationStatus": {
"State": 2,
"ErrorReasons": [
1,2,3
]
},
}
I can extract the Id, RegistrationStatus, and State, however I'm struggling with getting the list of ints out of the ErrorReasons list.
My starting Extract
#result =
EXTRACT
[id] string
,[RegistrationStatus] string
FROM #inputFileDaily
USING new Microsoft.Analytics.Samples.Formats.Json.JsonExtractor();
Then I pull out the State, and ErrorReasons into their own fields
#pre =
SELECT JsonFunctions.JsonTuple(RegistrationStatus) ["State"] AS State,
JsonFunctions.JsonTuple(RegistrationStatus) ["ErrorReasons"] AS ErrorReasons_data
FROM #result;
#pre =
SELECT State,
JsonFunctions.JsonTuple(ErrorReasons_data).Values AS ErrorReasons_Array
FROM #pre;
#CreateJSONTuple =
SELECT State,
JsonFunctions.JsonTuple(ErrorReasons)["0"] AS ErrorReason
FROM #pre
CROSS APPLY
EXPLODE(ErrorReasons_Array) AS c(ErrorReasons);
This of course gets nothing, cause it's looking for the field "0"
if I leave out the ["0"], then it complains about outputting a sqlmap<string,string> to csv. I've tried .Value, .Values, ["1"], [0], [1]
.Values doesn't work for me either of course.
I feel I'm really close, just missing a key operation to pull out the list of values from Error Reasons
with a little rubber ducking, and less over thinking it I figured it out,
#CreateJSONTuple =
SELECT
A.ErrorReason AS Reason
FROM #pre
CROSS APPLY
EXPLODE (ErrorReasons_Array) AS A(ErrorReason);
and having found the correct documentation to follow
https://learn.microsoft.com/en-us/u-sql/data-types/built-in/complex-built-in-u-sql-types

Get Only unique values from an array

I have an array of arrays and I need to get only unique values empname and dept from that array without depending on hoursWorked.
def data = [[empname:'Test1',dept:10,hoursWorked:6],
[empname:'Test1',dept:10,hoursWorked:2],
[empname:'Test2',dept:10,hoursWorked:10]] as Set
println data;
I used Set so that it contains only unique values. Since hoursWorked is different I am getting all the three values.
I want the expected result to be:
[[empname:Test1, dept:10],[empname:Test2, dept:10]]
You can cast a list of maps to a set of maps, but first, you need to transform the list to contain only the map entries you are interested in. Consider the following example:
data.collect { [empname: it.empname, dept: it.dept] }.toSet()
In the first run, it transforms each map to a map that contains only the two keys, and after that, it transforms a list to a set, so it contains only unique pairs of empname and dept.
It produces expected output:
[[empname:Test1, dept:10], [empname:Test2, dept:10]]
Yeah, that won't work as the values are different.
You can write a comparison closure for your data and pass it to unique
Take care though, as unique mutates the original list
def data = [
[empname:'Test1',dept:10,hoursWorked:6],
[empname:'Test1',dept:10,hoursWorked:2],
[empname:'Test2',dept:10,hoursWorked:10]
]
println data.unique { a, b -> a.empname <=> b.empname ?: a.dept <=> b.dept }
// Prints: [[empname:Test1, dept:10, hoursWorked:6], [empname:Test2, dept:10, hoursWorked:10]]
println data
// Prints: [[empname:Test1, dept:10, hoursWorked:6], [empname:Test2, dept:10, hoursWorked:10]]
// Original collection was mutated
You can use unique with a closure returning values that are only based on the keys you want to use:
data.unique{[it['empname'], it['dept']]}
===> [[empname:Test1, dept:10, hoursWorked:6],
[empname:Test2, dept:10, hoursWorked:10]]
data.unique{[it['empname'], it['dept']]} will let Groovy compute a collection of distinct values based on the empname and dept keys only. It's up to you to discard the hoursWorked keys.

Insert randomly generated strings as nested table

These days I am working on a small example/project of myself. What I am doing is creating n set of random strings of variable lengths. Here is what I want to obtain:
Two names of length from 3 to 25 characters.
A message ranging from 40 to 300 characters.
In my C example, I create a struct and kept inserting into this table as list. In my LUA example, I want a nested table like this:
tTableName = {
[1] = {
"To" = "Name 1",
"From" = "Name 2",
"Message" = "The first message generated"
}
[2] = {
"To" = "Name 3",
"From" = "Name 4",
"Message" = "The second message generated"
}
}
So, basically my structure goes like this:
struct PM {
char *sTo, *sFrom, *sMessage;
} PMs;
I want a similar structure/table in LUA so that I can use a table.insert method. I currently am doing it like this:
tTempTable = {
"To" = "Name 1",
"From" = "Name 2",
"Message" = "The first message generated"
}
table.insert( tTableName, tTempTable )
but I am thinking it as a wastage of a lot of processing time. Currently I am only generating a sample of 30 such PMs; but later I shall be generating *1000*s of them. Please advice.
i think you're falling into the trap of pre-maturely optimizing your code before you even know where a bottleneck is... but the following document contains a bunch of optimization info about lua in general, including tables. The guy who wrote it is one of the head architects for Lua.
http://www.lua.org/gems/sample.pdf
First of all, this isn't really a question. I'll guess you're asking if there's a more efficient way to do this? In general you want to write for clarity and don't sweat small performance gains at all unless you run into issues. But here are some notes about your code, including a few notes about efficiency:
The table constructor posted isn't valid. Either of the following fixes would work:
tTempTable = {
["To"] = "Name 1",
["From"] = "Name 2",
["Message"] = "The first message generated"
}
tTempTable = {
To = "Name 1",
From = "Name 2",
Message = "The first message generated"
}
You don't need to specify numerical indexes when constructing an array. You can replace this:
tTableName = {
[1] = { To = "Name 1", From = "Name 2", Message = "The first message generated" },
[2] = { To = "Name 3", From = "Name 4", Message = "The second message generated" },
}
With this, which means the exact same thing but is more succinct:
tTableName = {
{ To = "Name 1", From = "Name 2", Message = "The first message generated" },
{ To = "Name 3", From = "Name 4", Message = "The second message generated" },
}
This also happens to be more efficient; Lua can preallocate the array size it needs, whereas it's not smart enough to do that with the previous constructor.
As for a better way to write this in general, it's hard to say without knowing more about your application. If you're just trying to test some PM code, why not just generate the strings you need on the fly at the point of use? Why preallocate them into a table at all?
If you must preallocate, you don't have to store them as structured data. You could just have three arrays: ToNames, FromNames, Messages, then select from them at random at the point of use:
local to = ToNames [ math.random(1,#ToNames ) ]
local from = FromNames[ math.random(1,#FromNames) ]
local message = Messages [ math.random(1,#Messages ) ]
TestPM(to, from, message)

How does this work? Groovy Map creation with nested closures.

I'm rather new to Groovy, and recently created a canned message using a Map for testing. I created it using closures (not fully understanding, that's what I did, and changed it to the standard Map notation). Now I want to understand why the closure notation worked.
So the following two Maps get created properly. My question is how is Groovy interpreting the nested closures into a map?
Map notation:
Map m = [
person : [
first : "Flo",
middle : "Over",
last : "Stack"
],
address : [
street1 : "123 Any Street",
street2 : "2nd Floor",
city : "Anytown",
state : "YR",
zip : "99999"
]
]
Closure Notation:
Map m = {
person {
first "Flo"
middle "Over"
last "Stack"
}
address {
street1 "123 Any Street"
street2 "2nd Floor"
city "Anytown"
state "YR"
zip "99999"
}
}
Groovy has a special concept for creating tree structures called Builder. You can find more infos here: http://groovy.codehaus.org/Builders

Resources