Groovy groupBy on multiple properties and extracting only value - groovy

Having a list of elements:
List list = [
[category: 'A', name: 'a' value: 10],
[category: 'A', name: 'b' value: 20],
[category: 'B', name: 'a' value: 30],
[category: 'B', name: 'c' value: 40],
[category: 'B', name: 'd' value: 50],
]
I want to transform it into a nested map:
Map map = [
A: [a: 10, b: 20],
B: [a: 30, c: 40, d: 50],
]
The only solution I have come up with is to do something like this:
list.groupBy(
{ it.category }, { it.name }
).collectEntries { category, names ->
[(category): names.collectEntries { name, values ->
[(name): values.value[0]]
}]
}
However, I will have to deal with more than 2 levels of nesting in the future, and this approach will be unfeasible.
Is there any neat way to obtain the proper result in Groovy that will be more flexible?
EDIT:
By more than 2 levels of nesting I mean converting structure like:
List list = [
[category: 'A', subcategory: 'I', group: 'x', name: 'a', value: 10],
[category: 'A', subcategory: 'I', group: 'y', name: 'b', value: 20],
]
Into:
Map map = [
A: [I: [
x: [a: 10],
y: [b: 20],
]],
]
By adding nesting (depth) it would require more nested collectEntries calls, which will become unreadable.

I have found a neat solution to the problem by using Map's withDefault method and recursive Closure calls:
Map map = { [:].withDefault { owner.call() } }.call()
list.each {
map[it.category][it.name] = it.value
}
Or for the second case:
Map map = { [:].withDefault { owner.call() } }.call()
list.each {
map[it.category][it.subcategory][it.group][it.name] = it.value
}

Related

Comparing the values of common keys in multiple Nested Dictionaries

Below is the Input_dict for data analysis:
input_dict =
{
"C:\\arm64\\lib_apple.so": { "func-abc": [5,6,7,8], "func-123":[1,1,1,1] },
"C:\\arm64\\lib_banana.so": { "func-123": [2,3,4], "func-rt": [0,0] },
"C:\\armeabi\\lib_banana.so": { "func-123": [1,0,0], "func-rt": [1,5] },
"C:\\armeabi\\lib2.so": { "func-0": [1]},
"C:\\x86\\lib_apple.so": { "func-so": [5,6,7,8], "func-123": [2,2,1,1] },
"C:\\x86\\lib_banana.so": { "func-rt": [2,0] },
"C:\\x86\\lib2.so": { "func-0": [1,2,3]}
}
The aim is to compare the 'values' of functions with same name of different architectures(arm64,armeabi,x86).
In other words, I want to compare the "lists" of functions(with same name) in different libraries(.so) files.
For example: Comparing func-123: [2,3,4] with func-123: [1,0,0] from arm64\lib_banana.so and armeabi\lib_banana.so respectively.
One of the desired output could be:
{ lib_apple.so: { func-123: [arm64,[1,1,1,1]],[x86,[2,2,1,1]]}}
You can restructure your function data to order by their name first, then supported architectures. Afterwards, print out those functions that appear in multiple architectures:
from collections import defaultdict
from pathlib import PureWindowsPath
lib2func = {
r'C:\arm64\lib_apple.so': { 'func-abc': [5,6,7,8], 'func-123': [1,1,1,1] },
r'C:\arm64\lib_banana.so': { 'func-123': [2,3,4], 'func-rt': [0,0] },
r'C:\armeabi\lib_banana.so': { 'func-123': [1,0,0], 'func-rt': [1,5] },
r'C:\armeabi\lib.so': {},
r'C:\armeabi\lib2.so': { 'func-0': [1]},
r'C:\x86\lib_apple.so': { 'func-so': [5,6,7,8], 'func-123': [2,2,1,1] },
r'C:\x86\lib_banana.so': { 'func-rt': [2,0] },
r'C:\x86\lib2.so': { 'func-0': [1,2,3] },
}
# restructure
func2arch = defaultdict(dict)
for lib_path, functions in lib2func.items():
path = PureWindowsPath(lib_path)
lib = path.name
arch = path.parent.name
for func_name, func_val in functions.items():
func2arch[(lib, func_name)][arch] = func_val
# find functions defined for multiple architectures
for (lib, func_name), arch_data in func2arch.items():
if len(arch_data) < 2:
continue # skip functions that only appear once
print(lib, func_name, arch_data)
gives
lib_apple.so func-123 {'arm64': [1, 1, 1, 1], 'x86': [2, 2, 1, 1]}
lib_banana.so func-123 {'arm64': [2, 3, 4], 'armeabi': [1, 0, 0]}
lib_banana.so func-rt {'arm64': [0, 0], 'armeabi': [1, 5], 'x86': [2, 0]}
lib2.so func-0 {'armeabi': [1], 'x86': [1, 2, 3]}
The above code assumes that library/function name pairs are unique.

How to sort descending order with an Object result in NodeJs

I am using the below function to get number of duplicated values in an array.But i want to get this result sorted descending order with respect to the values.
function countRequirementIds() {
const counts = {};
const sampleArray = RIDS;
sampleArray.forEach(function(x) { counts[x] = (counts[x] || 0) + 1; });
console.log(typeof counts); //object
return counts
}
Output:
{
"1": 4,
"2": 5,
"4": 1,
"13": 4
}
required output:
{
"2": 5,
"1": 4,
"13": 4,
"4": 1,
}
Javascript object keys are unordered as explained here: Does JavaScript guarantee object property order?
So sorting objects by keys is impossible. However if order is of a matter for you I would suggest using array of tuples:
const arrayOfTuples = [
[ "1", 4],
[ "2", 5],
[ "4", 1],
[ "13", 4],
]
arrayOfTuples.sort((a,b) => b[1] - a[1]);
console.log(arrayOfTuples);
// => [ [ '2', 5 ], [ '1', 4 ], [ '13', 4 ], [ '4', 1 ] ]
The sort command. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort Arrays of objects can be sorted by comparing the value of one of their properties.

Elasticsearch order facets based on another index

I'm not sure of the right term to describe this problem so I'll go with a simple example.
I have blog posts index each with tags field (not_analyzed):
{
id: 1
tags: ['a']
},
{
id: 2
tags: ['a', 'b']
},
{
id: 3
tags: ['a', 'b', 'c']
}
and if I run search for tag:c I successfully get 3 post results and facets on tags:
{
term: 'a',
count: 3
},
{
term: 'b',
count: 2
}
In the result above, the facets are ordered by count. My question is, if it's possible to boost their values calculated from another index? If I have another index for tags with scores (arbitrary)
{
tag: 'a',
score: 0
},
{
tag: 'b',
score: 10
},
{
tag: 'c',
score: 0
},
Is it possible to achieve the following facets with scores calculated from another index?
{
tag: 'b'
score: 12 //10 + 2, where 2 is the count
},
{
tag: 'b'
score: 3 //0 + 3, where 3 is the count
}
*I'm aware that facets are being deprecated and I should update my code to use aggregations.

Jqplot pie/donut chart seriesColors array not reused/repeated

I am using jqplot to draw pie-chart and donut-charts.
And I am using the 'seriesColors' to give customised colors to the slices http://www.jqplot.com/docs/files/jqplot-core-js.html#jqPlot.seriesColors
seriesColors : [ "0571B0", "#5E3C99", "#008837"]
If the data(array-values to be passed) has only three values, then it does display the colors properly.
But if there are more than 3 values, it just displays that slice in black color.
It doesn't repeat/reuse the colors from the beginning (as said in the documentation).
Here it is:
var s2 = [['a', 8], ['b', 12], ['c', 6]];
var plot1 = $.jqplot('div_1', [s2], {
title: 'Chart 1',
seriesDefaults:{
renderer:$.jqplot.DonutRenderer ,
rendererOptions:{
startAngle: -90,
innerDiameter: 100,
showDataLabels: true,
dataLabels:'percent'
}
},
seriesColors: ["#0571B0", "#5E3C99", "#008837"],
highlighter: {
show: true
},
legend: { show:true, rendererOptions: {numberRows: 1}, location: 's', placement: 'outsideGrid'}
});
But if I add a 4th value in the array, the colors are not reused.
i.e if I modify the above array to
var s2 = [['a', 8], ['b', 12], ['c', 6], ['d', 9]];
Then the 4th slice ('d') is displayed in black color.
How do I fix this?
Found a fix to this.
Hope this helps out others who are facing a similar issue.
Here's the code.
var dataValues = [['a', 8], ['b', 12], ['c', 6], ['d', 9], ['e', 14]];
//Define the seriesColors array..
var seriesColors = ["#0571B0", "#5E3C99", "#008837"];
var seriesColorsLength = seriesColors.length;
var donutChartSeriesColors = new Array();
//Prepare a new array which would be passe to the chart..
//This will handle even if there are more value than the seriesColors array..
for(var i = 0; i < dataValues.length; i++) {
donutChartSeriesColors[i] = seriesColors[(seriesColorsLength-1) % i];
}
var plot1 = $.jqplot('div_1', [dataValues ], {
title: 'Chart 1',
seriesDefaults:{
renderer:$.jqplot.DonutRenderer ,
rendererOptions:{
startAngle: -90,
innerDiameter: 100,
showDataLabels: true,
dataLabels:'percent'
}
},
seriesColors: donutChartSeries,
highlighter: {
show: true
}
});

Get all CoudhDB documents which contain subset of view keys

Assume I have the following documents:
{
_id: 'id1',
tags: ['a', 'b']
}
{
_id: 'id2',
tags: ['b', 'c', 'd']
}
{
_id: 'id3',
tags: ['c', 'd', 'e']
}
Now I want to get all documents, where ALL tags are a subset of a given set. For example the view keys ['a','b','c','d'] should return doc 'id1' and 'id2' but not document with 'id3', because it contains the tag 'e' which is not in the requested keys.
How would you write such a view in CouchDB?

Resources