Combine two Groovy maps and get differences [duplicate] - grails

This question already has an answer here:
Compare two maps and find differences using Groovy or Java
(1 answer)
Closed 6 years ago.
I have two maps and I would like to combine this maps into new map with the differences. I mean with differences is if startDate or appId are different for that cuInfo and service.
Notice: The attributes cuInfo and service are unique in both maps.
Map 1:
[
[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"]
]
Map 2:
[
[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"]
]
I would like to get map below as final result:
[
[name:"Apple",cuInfo:"T12",service:"3",startDate:"14-02-16 10:00",appId:"G12351",startDate2:"14-01-16 13:22",appId2:"G12355"],
[name:"Apple",cuInfo:"T13",service:"3",startDate:"14-01-16 13:00",appId:"G12352",startDate2:"12-02-16 13:00",appId2:"G12356"],
[name:"Google",cuInfo:"T14",service:"9",startDate:"10-01-16 11:20",appId:"G12301",startDate2:"10-01-16 11:20",appId2:"G12300"]
]
I tried the code below but it gives not what I want:
def total = [list1: list1, list2: list2].collectEntries { label, maps ->
[(label): maps.countBy { it.iccId} ]
}.inject([:]) { result, label, counts ->
counts.entrySet().each { entry ->
if(!result[entry.key]) result[entry.key] = [:]
result[entry.key][(label)] = entry.value
}
result
}.collect { iccId , counts -> [iccId: iccId] << counts }
The code above give me this, it merge the maps and count the cuInfos but I'm not able to get the differences:
[
[cuInfo:T12, list1:1, list2:1], [cuInfo:T13, list1:1, list2:1], [cuInfo:T14, list1:1, list2:1], [cuInfo:T15, list1:1, list2:1],[cuInfo:T16, list1:1]
]
Please who can help to get it work please with example. Thanks

Is that what you're looking for:
def col1 = [
[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"]
]
def col2 = [
[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"]
]
col1
.findAll { it.cuInfo in col2.cuInfo && !(it.subMap('cuInfo', 'service', 'startDate', 'appId') in col2) }
.collect {
def e = col2.find { i2 -> it.cuInfo == i2.cuInfo }
it << [startDate2: e.startDate, appId2: e.appId]
}
.each {
println it
}
?

Related

How to pass different values to Pipeline Parameters

suppose if i am doing hyper parameter tuning to one of my model, lets say, i am using AdaBoostClassifier() and want to pass different base_estimator, so i pass SVC & DecisionTreeClassifier as estimator
_parameters=[
{
'mdl':[AdaBoostClassifier(random_state=23)],
'mdl__learning_rate':np.linspace(0,1,20),
'mdl__base_estimator':[SVC(),DecisionTreeClassifier()]
}
]
now, i want to pass different values to ccp_alpha of DecisionTreeClassifier, something like this
'mdl__base_estimator':[LinearRegression(),DecisionTreeClassifier(ccp_alpha=[0.1,0.2,0.3,0.4])]
how can i do that, i tried passing it like this, but it is not working, here is my entire code
pipeline=Pipeline(
[
('scal',StandardScaler()),
('mdl','passthrough')
]
)
_parameters=[
{
'mdl':[DecisionTreeClassifier(random_state=42)] ,
'mdl__max_depth':np.linspace(2,30,2),
'mdl__min_samples_split':np.linspace(1,10,1),
'mdl__max_features':np.linspace(1,100,1),
'mdl__ccp_alpha':np.linspace(0,1,10)
}
,{
'mdl':[AdaBoostClassifier(random_state=23)],
'mdl__learning_rate':np.linspace(0,1,20),
'mdl__base_estimator':[SVC(),DecisionTreeClassifier(ccp_alpha=[0.3,0.4,0.5,0.7])]
}
]
grid_search=GridSearchCV(_pipeline,_parameters,cv=3,n_jobs=-1,scoring='f1')
grid_search.fit(x,y
)
This kind of splitting is why param_grid can be a list of dicts, as in your outer split; but it cannot easily handle the nested disjunction you have. Two approaches come to mind.
More disjoint grids:
_parameters=[
{
'mdl': [DecisionTreeClassifier(random_state=42)],
'mdl__max_depth': np.linspace(2,30,2),
'mdl__min_samples_split': np.linspace(1,10,1),
'mdl__max_features': np.linspace(1,100,1),
'mdl__ccp_alpha': np.linspace(0,1,10),
},
{
'mdl': [AdaBoostClassifier(random_state=23)],
'mdl__learning_rate': np.linspace(0,1,20),
'mdl__base_estimator': [SVC()],
},
{
'mdl': [AdaBoostClassifier(random_state=23)],
'mdl__learning_rate': np.linspace(0,1,20),
'mdl__base_estimator': [DecisionTreeClassifier()],
'mdl__base_estimator__ccp_alpha': [0.3,0.4,0.5,0.7],
},
]
Or list comprehension:
_parameters=[
{
'mdl': [DecisionTreeClassifier(random_state=42)],
'mdl__max_depth': np.linspace(2,30,2),
'mdl__min_samples_split': np.linspace(1,10,1),
'mdl__max_features': np.linspace(1,100,1),
'mdl__ccp_alpha': np.linspace(0,1,10),
},
{
'mdl': [AdaBoostClassifier(random_state=23)],
'mdl__learning_rate': np.linspace(0,1,20),
'mdl__base_estimator': [SVC()] + [DecisionTreeClassifier(ccp_alpha=a) for a in [0.3,0.4,0.5,0.7]],
},
]

Adding blank rows in a set of data in Google Sheets

I have a set of data. What i am looking forwards is to add 2 blank rows after each set of 3 values like this
Hope to get help in getting this solved.
you can find the sample google sheet here : https://docs.google.com/spreadsheets/d/11nMvUWn3xcTfxlk4v30KruPr03HSheMk1jrxZPpJ_p4/edit?usp=sharing
Thanks
Shijilal
Solution:
IF it's the third row, Add 3 bunnies separated by a space, else keep the values as it is
JOIN them all and SPLIT by a bunny and TRANSPOSE
Sample:
=ARRAYFORMULA(TRANSPOSE(SPLIT(TEXTJOIN("🐇",1,IF(MOD(ROW(A2:A16),3)=1,A2:A16&REPT("🐇 ",3),A2:A16)),"🐇")))
Some time ago, I created this custom function that may help you. I changed it slightly to meet your requirement and added it to the script editor.
function rowsBetween(range, s, rowsWithData, text) {
var n = [],
a = [],
i = 0;
while (i < s) {
a.push(text
)
i++;
}
range.forEach(function(r, i) {
n.push(r);
if((i + 2) % rowsWithData == 1) {
a.forEach(function(x) {
n.push(x);
});
}
});
return n;
}
This script will allow you to enter in the spreadsheet this (custom) formula (see also cell E2)
=rowsBetween(A2:A16, 2, 12,)
See if that works for you?

Combining lists into tuples in list comprehension

A = [ [1,2,3],[4,5,6]].
B = [ [a,b,c],[d,e,f]].
The output should be:
[ [{1,a},{2,b},{3,c}],[{4,d},{5,e},{6,f}]].
This is what I have got so far.
Input: [ [{Y} || Y<-X ] || X<-A].
Output: [[{1},{2},{3}],[{4},{5},{6}]]
I think this is what you need:
[lists:zip(LA, LB) || {LA, LB} <- lists:zip(A, B)].
You need to zip both lists to be able to work with their elements together.

Group and sum collection in Groovy

I have a collection of objects that I want to group by month and name and sum total:
def things = [
[id:1, name:"fred", total:10, date: "2012-01-01"],
[id:2, name:"fred", total:10, date: "2012-01-03"],
[id:3, name:"jane", total:10, date: "2012-01-04"],
[id:4, name:"fred", total:10, date: "2012-02-11"],
[id:5, name:"jane", total:10, date: "2012-01-01"],
[id:6, name:"ted", total:10, date: "2012-03-21"],
[id:7, name:"ted", total:10, date: "2012-02-09"]
];
I would like the output to be:
[
"fred":[[total:20, month:"January"],[total:10, month:"February"]],
"jane":[[total:20,month:"January"]],
"ted" :[[total:10, month:"February"],[total:10, month:"March"]]
]
or something along those lines. What is the best way to accomplish this using groovy/grails?
The following lines
things.inject([:].withDefault { [:].withDefault { 0 } } ) {
map, v -> map[v.name][Date.parse('yyyy-MM-dd', v.date).format('MMMM')] += v.total; map
}
will give you this result:
[fred:[January:20, February:10], jane:[January:20], ted:[March:10, February:10]]
(works with Groovy >= 1.8.7 and 2.0)
I ended up with
things.collect {
// get the map down to name, total and month
it.subMap( ['name', 'total' ] ) << [ month: Date.parse( 'yyyy-MM-dd', it.date ).format( 'MMMM' ) ]
// Then group by name first and month second
}.groupBy( { it.name }, { it.month } ).collectEntries { k, v ->
// Then for the names, collect
[ (k):v.collectEntries { k2, v2 ->
// For each month, the sum of the totals
[ (k2): v2.total.sum() ]
} ]
}
To get the same result as Andre's much shorter, much better answer ;-)
Edit
bit shorter, but still not as good...
things.groupBy( { it.name }, { Date.parse( 'yyyy-MM-dd', it.date ).format( 'MMMM' ) } ).collectEntries { k, v ->
[ (k):v.collectEntries { k2, v2 ->
[ (k2): v2.total.sum() ]
} ]
}
Here's a solution to do the same thing as the other solutions, but in parallel using GPars. There may be a tighter solution, but this one does work with the test input.
#Grab(group='org.codehaus.gpars', module='gpars', version='1.0.0')
import static groovyx.gpars.GParsPool.*
//def things = [...]
withPool {
def mapInner = { entrylist ->
withPool{
entrylist.getParallel()
.map{[Date.parse('yyyy-MM-dd', it.date).format('MMMM'), it.total]}
.combine(0) {acc, v -> acc + v}
}
}
//for dealing with bug when only 1 list item
def collectSingle = { entrylist ->
def first = entrylist[0]
return [(Date.parse('yyyy-MM-dd', first.date).format('MMMM')) : first.total]
}
def result = things.parallel
.groupBy{it.name}.getParallel()
.map{ [(it.key) : (it.value?.size())>1?mapInner.call(it.value):collectSingle.call(it.value) ] }
.reduce([:]) {a, b -> a + b}
println "result = $result"
}

converting set to a map groovy

I have my logic in my postprocess to process the values of devices and files as below :(changed this to set from map as it was overriding the values)
def deviceFiles = devices.inject([] as Set) { deviceFiles, device ->
def v = device.key.split( /\./ )[0]
deviceFiles << [ (device.value), files[ v ] ]
}
output : deviceFiles :[[Acer C6, Tetris.apk], [Motorola Droid Milestone, Tetris.apk], [Acer C6, TheSims3.apk], [HTC Desire, TheSims3.apk]] --- looks good to be displayed
These values are to be passed as a map/properties so that the data would be displayed properly without any cast exceptions, which I am finding tough..
when it is looped through the set
deviceFiles.each { device ->
mapping.put("${device}", "${file}")
}
output : mapping :[HTC Desire:TheSims3.apk, Motorola Droid Milestone:Tetris.apk, Acer C6:Tetris.apk] -- which is not correct (Acer C6:TheSims3.apk has been overriden)
Am I missing something here in sending the expected values into map? or it is not possible to send the values of set through map(as map always eliminates the duplicates when i am iterating through devices) ???
You could use collectEntries:
def deviceFiles = devices.collectEntries {
device -> [device.value, device.key.split(/\./)[0]]
}
You can use groupBy for this. Assuming your set consists of:
def deviceFiles = [["Acer", "test.apk"], ["Acer", "abc.apk"], ["HTC", "qwer.apk"]]
def mapping = deviceFiles.groupBy { it[0] }
Will result in:
["Acer": [["Acer", "test.apk"], ["Acer", "abc.apk"]], "HTC": [["HTC", "qwer.apk"]]]

Resources