I have this data
Country:"USA", Gender:"Male", Count:100
Country:"USA", Gender:"Male", Count:300
Country:"USA", Gender:"Female", Count:200
Country:"USA", Gender:"Non-binary", Count:50
Country:"France", Gender:"Male", Count:10
Country:"France", Gender:"Female", Count:30
Country:"France", Gender:"Female", Count:10
As you can see, I have several lines with the same combination of Country & Gender.
I need to create a new map - group Country & Gender and sum the Count for this group.
I can arrange the map as I wish –
[Country:"USA", Gender:"Male", Count:100]
or
[[Country:"USA", Gender:"Male"]:100]]
My Questions:
How to best create the map for grouping
How to sum the groups
Thanks!
Simple groupBy with some additions:
List data = [
[Country:"USA", Gender:"Male", Count:100],
[Country:"USA", Gender:"Male", Count:300],
[Country:"USA", Gender:"Female", Count:200],
[Country:"USA", Gender:"Non-binary", Count:50],
[Country:"France", Gender:"Male", Count:10],
[Country:"France", Gender:"Female", Count:30],
[Country:"France", Gender:"Female", Count:10],
]
Map groupped = data.groupBy{ [ Country:it.Country, Gender:it.Gender ] }
groupped.each{ group, vals -> group.sum = vals*.Count.sum() }
println groupped.entrySet().join( '\n' )
prints
{Country=USA, Gender=Male, sum=400}=[{Country=USA, Gender=Male, Count=100}, {Country=USA, Gender=Male, Count=300}]
{Country=USA, Gender=Female, sum=200}=[{Country=USA, Gender=Female, Count=200}]
{Country=USA, Gender=Non-binary, sum=50}=[{Country=USA, Gender=Non-binary, Count=50}]
{Country=France, Gender=Male, sum=10}=[{Country=France, Gender=Male, Count=10}]
{Country=France, Gender=Female, sum=40}=[{Country=France, Gender=Female, Count=30}, {Country=France, Gender=Female, Count=10}]
You can grab map's keys:
println groupped.keySet().join( '\n' )
you'll get:
[Country:USA, Gender:Male, sum:400]
[Country:USA, Gender:Female, sum:200]
[Country:USA, Gender:Non-binary, sum:50]
[Country:France, Gender:Male, sum:10]
[Country:France, Gender:Female, sum:40]
Related
How can I sort a list of maps/objects by a specific key in Terraform?
Example:
[
{"name":"b", "value":"some value"},
{"name":"c", "value":"some value"},
{"name":"a", "value":"some value"},
{"name":"d", "value":"some value"}
]
Desired output
[
{"name":"a", "value":"some value"},
{"name":"b", "value":"some value"},
{"name":"c", "value":"some value"},
{"name":"d", "value":"some value"}
]
If you just want to sort by name, Matt's comment is best. But if you want something else, e.g. sorting by value with possible duplicates, you can do it as follows:
locals {
in_list = [
{"name":"b", "value":"some value3"},
{"name":"c", "value":"some value1"},
{"name":"a", "value":"some value5"},
{"name":"d", "value":"some value5"}
]
#get sorted values (not names) with possible duplicates
sorted_values = distinct(sort(local.in_list[*].value))
sorted_list = flatten(
[for value in local.sorted_values:
[ for elem in local.in_list:
elem if value == elem.value
]
])
}
nlapi allows to use joins to refer to values in another record or a sublist, when searching for a record. E.g. if there is a record FOO
FOO: {
type: 'rectype',
field1: '111',
sublists:
bar: [
{value: 1,}, {value: 2,}
]
}
I can search for this record with a query, provided there is a join, let's say, bar to the bar sublits:
nlapiSearchRecord('rectype', null,
[
['field', 'equalto', 'bar',],
'and',
['bar.value', 'equalto', '1',],
],
[ new nlobjSearchColumn('anotherfield', null, null), ]
);
This works. And the question is: is there a way to find a record (the one from the example) by specifying more sublist values, like:
nlapiSearchRecord('rectype', null,
[
['field', 'equalto', 'bar',],
'and',
['bar.value', 'equalto', '1',],
'and',
['bar.value', 'equalto', '2',],
],
[ new nlobjSearchColumn('anotherfield', null, null), ]
);
I've tried numerous approaches with different expressions, but it finds nothing with such a query.
A more concrete example is to find a bomrevision, which has specific components and bomquantities (the commented code is just for demonstration purposes of some approaches with the filter expression I've tried):
nlapiSearchRecord('bomrevision', null, [
['isinactive', 'equalto', 'F',],
'and',
['component.item', 'is', '4942',],
'and',
['component.item', 'is', '4936',],
//[
// 'and',
// ['component.bomquantity', 'equalto', '38',],
//],
//'and',
//[
// ['component.item', 'anyof', '4936',],
// 'and',
// ['component.bomquantity', 'equalto', '38',],
//],
],
[ new nlobjSearchColumn('name', null, null), ]
);
Thank you
I understand your question to be "How can I find items where the component list includes multiple specified items?"
The challenge here is that when you join to the component list, NetSuite returns a result for each line in the list. This means any line that contains 'Item 1' will not contain 'Item 2' and vice versa, so no result meets the criteria.
You can work around this using the following approach:
Group the results by 'main' or 'parent' record ('FOO' or 'bomrevision' in your examples).
Use NS_CONCAT to give a field in each result that contains values from all the sublist results. (Note that NS_CONCAT is undocumented, so use at your own risk).
Use summary criteria formulae to inspect the concatenated field for each value of interest.
Example (tested with assembly items and their member items as I don't have access to an account with BOM revisions):
[
["type","anyof","Assembly"],
"AND",
["min(formulatext: NS_CONCAT({memberitem.name}) )","contains","ITEM 1"],
"AND",
["min(formulatext: NS_CONCAT({memberitem.name}))","contains","ITEM 2"]
]
Or, for your 'bomrevision' (untested, adapted from above):
[
["min(formulatext: NS_CONCAT({component.item}) )","contains","4942"],
"AND",
["min(formulatext: NS_CONCAT({component.item}))","contains","4936"]
]
Be aware that under some circumstances NetSuite will default to returning the text of a list field rather than the value. If this is the case (and the values shown in your example are internal IDs as I'm assuming), you may need to replace component.item with component.item.id, or change the search values to the text name instead.
There may be a more straightforward way of doing this so I'd be glad to hear from anyone with a better solution.
Edit in response to request in comments:
Here is the full code of a working example in my account:
var assemblyitemSearch = nlapiSearchRecord("assemblyitem",null,
[
["type","anyof","Assembly"],
"AND",
["min(formulatext: NS_CONCAT({memberitem.name}) )","contains","ITEM 1"],
"AND",
["min(formulatext: NS_CONCAT({memberitem.name}))","contains","ITEM 2"]
],
[
new nlobjSearchColumn("itemid",null,"GROUP").setSort(false),
new nlobjSearchColumn("displayname",null,"GROUP"),
new nlobjSearchColumn("salesdescription",null,"GROUP"),
new nlobjSearchColumn("formulatext",null,"MIN").setFormula("NS_CONCAT({memberitem})")
]
);
This is an Item search filtering by Member Items, as the closest thing in my account to the BOM Revisions in the example. The only change I have made is to replace the item names with "ITEM 1" and "ITEM 2". You would need to replace these with relevant items from your system.
I can go to a Sales Order page and open developer tools on my browser and add the above code to create a search, then append the following additional code to retrieve results and print out to the console:
var data = [];
assemblyitemSearch.forEach(r => {
var vals = {};
r.rawValues.forEach(v => {
vals[v.name] = v.value
});
data.push(vals);
});
console.table(data);
This returns a table with results exactly as expected.
Edit 2: Adding example using Sales Orders and Items as possibly more consistent between different accounts.
var salesorderSearch = nlapiSearchRecord("salesorder",null,
[
["type","anyof","SalesOrd"],
"AND",
["trandate","within","thismonth"],
"AND",
["min(formulatext: NS_CONCAT({item}))","contains","ITEM 1"],
"AND",
["min(formulatext: NS_CONCAT({item}))","contains","ITEM 2"]
],
[
new nlobjSearchColumn("trandate",null,"GROUP"),
new nlobjSearchColumn("tranid",null,"GROUP"),
new nlobjSearchColumn("formulatext",null,"MIN").setFormula("NS_CONCAT({item})")
]
);
The code given in the documentation requires the column attribute and the corresponding JSON column mapping. But I have a dataset having 100+columns and I don't want to map them manually. Is there a function in tabulator that creates the table with the original column names given in JSON. I tried SetData Function but it doesn't work. I tried to remove the columns attribute from the below code but it still doesn't work (Tables are not displayed in the web).
Code given in the documentation is not working:
var table = new Tabulator("#example-table", {
index:"age", //set the index field to the "age" field.
});
var tableData = [
{id:1, name:"Billy Bob", age:"12", gender:"male", height:1, col:"red", dob:"", cheese:1},
{id:2, name:"Mary May", age:"1", gender:"female", height:2, col:"blue", dob:"14/05/1982", cheese:true},
]
table.setData(tableData);
Code working only with Column attributes:
var table = new Tabulator("#example-table", {
index:"age", //set the index field to the "age" field.
});
var tableData = [
{id:1, name:"Billy Bob", age:"12", gender:"male", height:1, col:"red", dob:"", cheese:1},
{id:2, name:"Mary May", age:"1", gender:"female", height:2, col:"blue", dob:"14/05/1982", cheese:true},
]
var table = new Tabulator("#example-table", {
data:tableData, //set initial table data
columns:[
{title:"Name", field:"name"},
{title:"Age", field:"age"},
{title:"Gender", field:"gender"},
{title:"Height", field:"height"},
{title:"Favourite Color", field:"col"},
{title:"Date Of Birth", field:"dob"},
{title:"Cheese Preference", field:"cheese"},
],
});
Not a function, but a table constructor property:
http://tabulator.info/docs/4.3/columns#autocolumns
Say I have the following documents:
{"_key": "1", "name": "George Washington"}
{"_key": "2", "name": "George Washington"}
{"_key": "3", "name": "John Adams"}
{"_key": "4", "name": "Thomas Jefferson"}
{"_key": "5", "name": "George Washington"}
{"_key": "6", "name": "Thomas Jefferson"}
I want to write an AQL statement that returns the keys of the document grouped by name, but only if the name occurs more than once.
So my desired output is:
[["1", "2", "5"], ["4", "6"]]
So far I have come up with
FOR doc IN documents
LET key = doc._key
COLLECT name = doc.name INTO groups KEEP key
RETURN (FOR g IN groups RETURN g["key"])
This returns:
[["1", "2", "5"], ["3"], ["4", "6"]]
How can I modify the AQL command to only get arrays with two or more entries?
Another possibility (potentially a bit more efficient as no subquery is involved):
FOR doc IN documents
LET key = doc._key
COLLECT name = doc.name INTO groups KEEP key
LET keys = groups[*].key
FILTER LENGTH(keys) > 1
RETURN keys
Solved it:
FOR doc IN documents
LET key = doc._key
COLLECT name = doc.name INTO groups KEEP key
LET groups2 = (FOR group IN groups RETURN group["key"])
FILTER LENGTH(groups2) >= 2
RETURN groups2
I have a List of Map with nested Map as well as below :-
def list = [
[
"description": "The issue is open and ready for the assignee to start work on it.",
"id": "1",
"name": "Open",
"statusCategory": [
"colorName": "blue-gray",
"id": 2,
"key": "new",
"name": "To Do",
]
],
[
"description": "This issue is being actively worked on at the moment by the assignee.",
"id": "3",
"name": "In Progress",
"statusCategory": [
"colorName": "yellow",
"id": 4,
"key": "indeterminate",
"name": "In Progress",
]
]
]
I have a task to get List of subMap with nested subMap. I'm doing some thing like as below :-
def getSubMap = { lst ->
lst.findResults { it.subMap(["id", "name", "statusCategory"])}
}
println getSubMap(list)
But its give me output as below :-
[
[
"id":1,
"name":"Open",
"statusCategory":[
"colorName":"blue-gray",
"id":2,
"key":"new",
"name":"To Do"
]
],
[
"id":"3",
"name":"In Progress",
"statusCategory":[
"colorName":"yellow",
"id":"4",
"key":"indeterminate",
"name":"In Progress"
]
]
]
As you can see I'm unable to get subMap of statusCategory key Map. Actually I want to get further subMap for nested Maps something like as below :-
[
[
"id":1,
"name":"Open",
"statusCategory":[
"id":"2",
"name":"To Do"
]
],
[
"id":"3",
"name":"In Progress",
"statusCategory":[
"id":"4",
"name":"In Progress"
]
]
]
To achieve this I'm trying as below :-
def getSubMap = { lst ->
lst.findResults { it.subMap(["id", "name", "statusCategory":["id","name"]])}
}
def modifiedList = getSubMap(list)
But it throws me Excpetion. And If I'm doing as below :-
def getSubMap = { lst ->
lst.findResults { it.subMap(["id", "name", "statusCategory"]).statusCategory.subMap(["id","name"])}
}
println getSubMap(list)
It gives only nested subMap as :-
[["id":"2", "name":"To Do"], ["id":"4", "name":"In Progress"]]
could anyone suggest me how to recurselvely find List of subMap with nested subMap if exist?
If your Map nesting is arbitrary, then you might want to consider something like this:
def nestedSubMap
nestedSubMap = { Map map, List keys ->
map.subMap(keys) + map.findAll { k, v -> v instanceof Map }.collectEntries { k, v -> [(k):nestedSubMap(v, keys)] }
}
Given your input and this closure, the following script:
def result = list.collect { nestedSubMap(it, ["id", "name"]) }
println '['
result.each { print it; println ',' }
println ']'
Produces this output:
[
[id:1, name:Open, statusCategory:[id:2, name:To Do]],
[id:3, name:In Progress, statusCategory:[id:4, name:In Progress]],
]
Given the original list, consider this:
def resultList = list.collect {
def fields = ["id", "name"]
def m = it.subMap(fields)
m["statusCategory"] = it["statusCategory"].subMap(fields)
return m
}
which supports these assertions:
assert 1 == resultList[0]["id"] as int
assert "Open" == resultList[0]["name"]
assert 2 == resultList[0]["statusCategory"]["id"] as int
assert "To Do" == resultList[0]["statusCategory"]["name"]
assert 3 == resultList[1]["id"] as int
assert "In Progress" == resultList[1]["name"]
assert 4 == resultList[1]["statusCategory"]["id"] as int
assert "In Progress" == resultList[1]["statusCategory"]["name"]