How to group array items based on multiple keys in Javascript / Jquery - javascript

I have an Javascript array as below
var data = [{
"Ticket_id": "239248",
"Order_Issue": "SAP",
"Region": "EU",
"Line_No": "10",
"Line_Issue": "Qty not available",
"Serial_Number": "72CEP92"
},
{
"Ticket_id": "239248",
"Order_Issue": "SAP",
"Region": "EU",
"Line_No": "20",
"Line_Issue": "contact info missing",
"Serial_Number": "2198IE3"
}];
I want to group my array by multiple keys. The result should look as below :
var data = [{
"Ticket_id": "239248",
"Order_Issue": "SAP",
"Region": "EU",
"Lines" : [
{"Line_No": "10",
"Line_Issue": "Qty not available",
"Serial_Number": "72CEP92"},
{"Line_No": "20",
"Line_Issue": "contact info missing",
"Serial_Number": "2198IE3"}]
}];
So basically, I will group by Ticket_id, Order_Issue and Region. And I will add Items subarray where I will store all the Line_No, Line_Issue and Serial_Number.
I succeeded to group only by one key let's say by Ticket_id as the below example. When I add another key to my object obj[item."Order_Issue] = obj[item."Order_Issue] || [];, the group by will be done only on that key and ignore the previous key. Any suggestions please what am I doing wrong and how to get the exact format I want. Thank you.
var data = [{
"Ticket_id": "239248",
"Order_Issue": "SAP",
"Region": "EU",
"Line_No": "10",
"Line_Issue": "Qty not available",
"Serial_Number": "72CEP92"
},
{
"Ticket_id": "239248",
"Order_Issue": "SAP",
"Region": "EU",
"Line_No": "20",
"Line_Issue": "contact info missing",
"Serial_Number": "2198IE3"
},
{
"Ticket_id": "239267",
"Order_Issue": "Online Payment",
"Region": "EU",
"Line_No": "10",
"Line_Issue": "card expired",
"Serial_Number": "21BBF03"
}];
var group_Line_No = data.reduce(function (obj, item) {
obj[item.Ticket_id] = obj[item.Ticket_id] || [];
obj[item.Ticket_id].push(item.Line_No);
return obj;
}, {});
console.log(group_Line_No);
var groups = Object.keys(group_Line_No).map(function (key) {
return {Ticket_id: key, Line_No: group_Line_No[key]};
});
console.log(groups);

If you want a dynamic solution for any mix of keys you could use reduce method and inside use for...of loop and check if the current property is key to group by or should be added to new object in Lines array.
var data = [{"Ticket_id":"239248","Order_Issue":"SAP","Region":"EU","Line_No":"10","Line_Issue":"Qty not available","Serial_Number":"72CEP92"},{"Ticket_id":"239248","Order_Issue":"SAP","Region":"EU","Line_No":"20","Line_Issue":"contact info missing","Serial_Number":"2198IE3"},{"Ticket_id":"239267","Order_Issue":"Online Payment","Region":"EU","Line_No":"10","Line_Issue":"card expired","Serial_Number":"21BBF03"}]
const groupBy = keys => data.reduce((r, e) => {
const key = keys.map(k => e[k]).join('|');
const obj = {}
for (let [k, v] of Object.entries(e)) {
if (!r[key]) r[key] = {Lines: []}
if (keys.includes(k)) {
r[key][k] = v
} else {
obj[k] = v
}
}
r[key].Lines.push(obj)
return r;
}, {});
const result = groupBy(['Ticket_id', 'Order_Issue', 'Region'])
console.log(Object.values(result))

Use a similar method, but combine all the key properties into the keys of the intermedia result object.
var data = [{
"Ticket_id": "239248",
"Order_Issue": "SAP",
"Region": "EU",
"Line_No": "10",
"Line_Issue": "Qty not available",
"Serial_Number": "72CEP92"
},
{
"Ticket_id": "239248",
"Order_Issue": "SAP",
"Region": "EU",
"Line_No": "20",
"Line_Issue": "contact info missing",
"Serial_Number": "2198IE3"
},
{
"Ticket_id": "239267",
"Order_Issue": "Online Payment",
"Region": "EU",
"Line_No": "10",
"Line_Issue": "card expired",
"Serial_Number": "21BBF03"
}
];
var group_Line_No = data.reduce(function(obj, item) {
let key = `${item.Ticket_id}.${item.Order_Issue}.${item.Region}`;
obj[key] = obj[key] || {
Ticket_id: item.Ticket_id,
Order_Issue: item.Order_Issue,
Region: item.Region,
Lines: []
};
obj[key].Lines.push({
Line_No: item.Line_No,
Line_Issue: item.Line_Issue,
Serial_Number: item.Serial_Number
});
return obj;
}, {});
var groups = Object.values(group_Line_No);
console.log(groups);

Your on the right track.
You can create an id by combining the Ticket_id, Order_Issue, Region when processing an entry. Then push the line data.
const groupEntries = arr =>
Object.values(
arr.reduce(
(
obj,
{ Ticket_id, Order_Issue, Region, Line_No, Line_Issue, Serial_Number }
) => {
const id = [Ticket_id, Order_Issue, Region].join('#') // unique id
obj[id] = obj[id] || { Ticket_id, Order_Issue, Region, Lines: [] }
obj[id].Lines.push({ Line_No, Line_Issue, Serial_Number }) // push new line data
return obj
},
{}
)
)
const data = [
{
Ticket_id: '239248',
Order_Issue: 'SAP',
Region: 'EU',
Line_No: '10',
Line_Issue: 'Qty not available',
Serial_Number: '72CEP92',
},
{
Ticket_id: '239248',
Order_Issue: 'SAP',
Region: 'EU',
Line_No: '20',
Line_Issue: 'contact info missing',
Serial_Number: '2198IE3',
},
{
Ticket_id: '239267',
Order_Issue: 'Online Payment',
Region: 'EU',
Line_No: '10',
Line_Issue: 'card expired',
Serial_Number: '21BBF03',
},
]
const result = groupEntries(data)
console.log(result)

Related

Can't Use MAP data structure in Node.js

I have getting some issue in map program in node.js. I am trying to use MAP into node.js program and I am not getting value.I have write some code to use map however I think it not working as its not go into the loop to fetch the key-value.
Please find below program
async CreateProduceMVPRateAsset(data, callback) {
var ProducePRICE = {};
var MVPPRICE =[];
var MVPPRICE_BS ={};
var MVPPRICE_LB ={};
//var ASKINGPRICE= {}// put all the things which need to go to blockchain
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
console.log('Data', data);
console.log('Username', data.username);
var PRODUCENAME = data.PRODUCE
console.log('PRODUCENAME', PRODUCENAME);
var COUNTRY = data.COUNTRY;
console.log('COUNTRY', COUNTRY);
var STATE = data.STATE;
console.log('STATE', STATE);
var MVPRATES = data.MVPRATES;
console.log('MVPRATERATE', MVPRATES);
const MVPRATE = new Map(MVPRATES);
// program could not go inside the for loop
for (const [k, v] of MVPRATE.entries()) {
console.log("Inside map", k, v)
MVPPRICE = v.RATE // should go in MVPPRICE
var Value = MVPPRICE[0].value // want to get first element value from MVPPRICE array
console.log('Value', Value);
var value_lb = Value/40;
console.log('value_lb', value_lb);
value_lb = Number((value_lb).toFixed(4));
console.log('If the value of BS provided controller come here');
MVPPRICE_LB.Value = value_lb
MVPPRICE_LB.QuantityUnit = 'LB'
MVPPRICE_LB.uidisplay = false
MVPPRICE_LB.CurrencyUnit = 'USD'
MVPPRICE.push(MVPPRICE_LB);
ProducePRICE.MVPPRICE = MVPPRICE
console.log('MVPPRICE',MVPPRICE);
console.log('ProducePRICE',ProducePRICE);
// mvpprice.totalPrice = totalPrice;
console.log('for pricing',totalPrice);
// ProducePRICE.VARIETY = VARIETY;
ProducePRICE.PRODUCENAME = PRODUCENAME;
ProducePRICE.STATE = STATE;
ProducePRICE.COUNTRY = COUNTRY;
}
JSON structure which I am sending using postman
{
"username": "admin2",
"PRODUCE": "Apple",
"STATE": "MI",
"COUNTRY": "US",
"MVPRATES": {
"fuji": {
"VARIETY": "fuji",
"RATE": [
{
"UNIT": "Bussel",
"CURRENCY": "USD",
"VALUE": 10.25,
"UIDISPLAY": true
}
]
},
"gala": {
"VARIETY": "gala",
"RATE": [
{
"UNIT": "Bussel",
"CURRENCY": "USD",
"VALUE": 10.25,
"UIDISPLAY": true
}
]
}
}
}
Output which I am getting:
Seems like you may want to do the following, this creates a Map with two entries, fuji and gala
const MVPRATES = {
"fuji": {
"VARIETY": "fuji",
"RATE": [{
"UNIT": "Bussel",
"CURRENCY": "USD",
"VALUE": 10.25,
"UIDISPLAY": true
}]
},
"gala": {
"VARIETY": "gala",
"RATE": [{
"UNIT": "Bussel",
"CURRENCY": "USD",
"VALUE": 10.25,
"UIDISPLAY": true
}]
}
}
const MVPRATE = new Map(Object.entries(MVPRATES));
for (const [k, v] of MVPRATE.entries()) {
console.log("Inside map", k, v)
}
Though, the need for Map is still unclear, as you can achieve the above with
const MVPRATES = {
"fuji": {
"VARIETY": "fuji",
"RATE": [{
"UNIT": "Bussel",
"CURRENCY": "USD",
"VALUE": 10.25,
"UIDISPLAY": true
}]
},
"gala": {
"VARIETY": "gala",
"RATE": [{
"UNIT": "Bussel",
"CURRENCY": "USD",
"VALUE": 10.25,
"UIDISPLAY": true
}]
}
}
for (const [k, v] of Object.entries(MVPRATES)) {
console.log("Inside map", k, v)
}

How to filter an array of objects based on another array of objects?

I have two array of objects like below
conditions= [
{
'condition': 'Expert',
'value': 'All'
},
{
'condition': 'Coach',
'value': 'willaim'
},
{
'condition': 'manager',
'value': 'Brandy Lovings'
},
{
'condition': 'site',
'value': 'ALL'
},
{
'condition': 'client',
'value': 'ALL'
}
]
data=[
{
"Date": "11/6/2018",
"client": "Verizon",
"Expert": "Ellison, Lauren",
"Coach": "willaim",
"manager": "Brandy Lovings",
"site": "Sundance",
"Metric": "STR"
},
{
"Date": "11/6/2018",
"client": "Amzaon",
"Expert": "Ellison, Lauren",
"Coach": "Dash Williamson",
"manager": "David",
"site": "abc",
"Metric": "STR"
}
]
I want to filter data array with the conditions array, like if condition property in conditions array contain Expert then I need to filter data array based on data.Expert = conditions[Expert Conditionindex].value then I need to return all the data with this conditions.
Another thing is, If value: 'ALL' then no need of filtering in that particular condition.
The desired output is like
filteredData = [
{
"Date": "11/6/2018",
"client": "Verizon",
"Expert": "Ellison, Lauren",
"Coach": "willaim",
"manager": "Brandy Lovings",
"site": "Sundance",
"Metric": "STR"
}
]
How do I solve this problem?
You could filter with a subset of conditions without ALL flag.
var conditions = [{ condition: "Expert", value: "All" }, { condition: "Coach", value: "willaim" }, { condition: "manager", value: "Brandy Lovings" }, { condition: "site", value: "ALL" }, { condition: "client", value: "ALL" }],
data = [{ Date: "11/6/2018", client: "Verizon", Expert: "Ellison, Lauren", Coach: "willaim", manager: "Brandy Lovings", site: "Sundance", Metric: "STR" }, { Date: "11/6/2018", client: "Amzaon", Expert: "Ellison, Lauren", Coach: "Dash Williamson", manager: "David", site: "abc", Metric: "STR" }],
filters = conditions.filter(({ value }) => value.toUpperCase() !== 'ALL'),
result = data.filter(o =>
filters.every(({ condition, value }) => o[condition] === value));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This should work for you:
const conditionsObj={}
conditions.filter(({value})=>value.toLowerCase()!=='all').forEach((condition)=>{
conditionsObj[condition.condition]=condition.value
})
const results=data.filter((item)=>{
let match=false;
Object.keys(conditionsObj).forEach((_key)=>{
if(conditionsObj[_key]===item[_key]){
match=true;
}
})
return match;
})
console.log(results)

How to separate array of objects with specific array prefix in typescript

I planed to prepare this array by separate those kind of array with index specification
Default data format
[{
"Emp_code": "EM-00001",
"Emp_title": "11",
"Emp_firstName": "22",
"Emp_lastName": "33",
"Emp_dateOfBirth": "20-10-1985",
"Con_title": "title",
"Con_email": "email",
"Con_addres": "address",
"Con_phone": "phone"
}]
Wanted format
[{
"emp": {
"code": "EM-00001",
"title": "11",
"firstName": "22",
"lastName": "33",
"dateOfBirth": "20-10-1985",
},
"con": {
"Con_title": "title",
"Con_email": "email",
"Con_addres": "address",
"Con_phone": "phone"
}
}]
You can reduce the property names to a starting accumulator of [{ emp: {} }, { con: {} }] and each iteration you can add the property to the corresponding item in the accumulator.
const data = [{
"Emp_code": "EM-00001",
"Emp_title": "11",
"Emp_firstName": "22",
"Emp_lastName": "33",
"Emp_dateOfBirth": "20-10-1985",
"Con_title": "title",
"Con_email": "email",
"Con_addres": "address",
"Con_phone": "phone"
}];
const format = obj =>
Object.getOwnPropertyNames(obj[0]).reduce(
(acc, prop) => {
if (prop.startsWith('Emp_')) {
acc[0].emp[prop.replace('Emp_', '')] = obj[0][prop];
} else {
acc[1].con[prop] = obj[0][prop];
}
return acc;
},
[{ emp: {} }, { con: {} }]
);
console.log(format(data));
var item = {
"Emp_code": "EM-00001",
"Emp_title": "11",
"Emp_firstName": "22",
"Emp_lastName": "33",
"Emp_dateOfBirth": "20-10-1985",
"Con_title": "title",
"Con_email": "email",
"Con_addres": "address",
"Con_phone": "phone"
}
var data = [item, item];
var res = []
for (var item of data) {
var temp = {};
res.push(temp);
for (var prop in item) {
var parts = prop.split('_');
var prefix = parts[0].toLowerCase();
temp[prefix] = temp[prefix] || {};
temp[prefix][prefix === 'emp' ? parts[1] : prop] = item[prop]
}
}
console.log(res);
Below script checks element using loops, then splits them into prefix & suffix. Then checks for whether prefix is present in resulting array or not. If it's not then adds that prefix into array & prepares the result.
var a = [{"Emp_code": "EM-00001", "Emp_title": "11", "Emp_firstName": "22", "Emp_lastName": "33", "Emp_dateOfBirth": "20-10-1985", "Con_title": "title", "Con_email": "email", "Con_addres": "address", "Con_phone": "phone"}];
var b = [];
$.each(a, function(arrKey, arrData){
var tempArr = {};
$.each(arrData, function(key, value){
var arrKey = key.split('_');
var prefix = arrKey[0];
var suffix = arrKey[1];
if( $.inArray(prefix, Object.keys(tempArr)) == -1 ) {
tempArr[prefix] = {};
}
tempArr[prefix][suffix]=value;
});
b.push(tempArr);
});
console.log(b);

Match two object keys and display another object key value in angular 4

i have two objects like this
languages = [
{
"name": "english",
"iso_639_2_code": "eng"
},
{
"name": "esperanto",
"iso_639_2_code": "epo"
},
{
"name": "estonian",
"iso_639_2_code": "est"
}
]
and another is
user = [
{
name: "john",
language: "eng",
country: "US"
}
];
what i have to do is, match iso_639_2_code to language of user then, i have to display Language name not code from languages. basically both are different api, and i have no idea how to do it this in angular 4.
here's a link what i am trying https://stackblitz.com/edit/angular-9k2nff?file=app%2Fapp.component.ts
Use array find:
var languages = [
{"name": "english", "iso_639_2_code": "eng"},
{"name": "esperanto","iso_639_2_code": "epo"},
{"name": "estonian","iso_639_2_code": "est"}
];
var user = [{name: "john",language: "eng",country: "US"}];
var language = languages.find(l => l.iso_639_2_code === user[0].language);
var languageName = language && language.name; // <-- also prevent error when there is no corresponding language found
console.log(languageName);
EDIT:
With multiple user, it will be:
var languages = [
{"name": "english", "iso_639_2_code": "eng"},
{"name": "esperanto","iso_639_2_code": "epo"},
{"name": "estonian","iso_639_2_code": "est"}
];
var users = [
{name: "john",language: "eng",country: "US"},
{name: "john",language: "epo",country: "Esperanto"}
];
var languageNames = languages.filter(
l => users.find(u => l.iso_639_2_code === u.language)
).map(lang => lang.name);
console.log(languageNames);
Use find
var output = languages.find(s => s.iso_639_2_code == user[0].language).name;
Demo
var languages = [{
"name": "english",
"iso_639_2_code": "eng"
},
{
"name": "esperanto",
"iso_639_2_code": "epo"
},
{
"name": "estonian",
"iso_639_2_code": "est"
}
];
var user = [{
name: "john",
language: "eng",
country: "US"
}
];
var output = languages.find(s => s.iso_639_2_code == user[0].language).name;
console.log(output);
Or, if there are multiple users, and you want to find language name for each of them, then use map
var output = user.map(t =>
languages.find(s =>
s.iso_639_2_code == t.language).name);
Demo
var languages = [{
"name": "english",
"iso_639_2_code": "eng"
},
{
"name": "esperanto",
"iso_639_2_code": "epo"
},
{
"name": "estonian",
"iso_639_2_code": "est"
}
];
var user = [{
name: "john",
language: "eng",
country: "US"
}
];
var output = user.map(t =>
languages.find(s =>
s.iso_639_2_code == t.language).name);
console.log(output);
I think here is what you need , for output just run the snippet :
var languages = [
{
"name": "english",
"iso_639_2_code": "eng"
},
{
"name": "esperanto",
"iso_639_2_code": "epo"
},
{
"name": "estonian",
"iso_639_2_code": "est"
}
];
var user = [
{
name: "john",
language: "eng",
country: "US"
}
];
user.map(u => {
let flang = languages.filter(lang => lang.iso_639_2_code === u.language);
if(flang) {
u.language = flang[0].name;
}
return u;
})
console.log(user);
var languages=[
{"name":"english","iso_639_2_code":"eng"},
{"name":"esperanto","iso_639_2_code":"epo"},
{"name":"estonian","iso_639_2_code":"est"}
];
var user=[
{name:"john",language:"eng",country:"US"}
];
var languageFound = languages.find(lang => lang.iso_639_2_code === user[0].language);
if(languageFound){
var languageName = languageFound.name;
console.log(languageName);
}

Organise element in a array

i'm searching a smart way to reoganise an array by a element inside it:
In entry i've got:
[{"name": "brevet",
"country": "fr"
},{
"name": "bac",
"country": "fr"
},{
"name": "des",
"country": "ca"
},{
"name": "dep",
"country": "ca"
}{
"name": "other",,
"country": "other"}]
I want to reorganize my array by country to have this in my output:
[{
"name": "fr",
"degrees": [
{
"name": "brevet",
"country": "fr"
},{
"name": "bac",
"country": "fr"
}]
},{
"name": "ca",
"degrees": [{
"name": "des",
"country": "ca"
},{
"name": "dep",
"country": "ca"
}]
},{
"name": "other",
"degrees": [{
"name": "other",
"country": "other"
}]
}]
For this i write a dirty function, but it seems to me there is a better way but i don't see how. If someone can ligth my brain in a better way to do this i'll be helpfull
private organizeDegrees(degrees: Array<SubscriptionFieldInterface>) {
let degreesByCountry = new Array();
let storeIndex = new Array();
degrees.map(degree => {
let index = null;
storeIndex.find((element, idx) => {
if (element === degree.country) {
index = idx;
return true;
}
});
if (index === null) {
index = degreesByCountry.length;
let newEntry = {
'name': degree.country,
'degrees': new Array()
};
storeIndex.push(degree.country);
degreesByCountry.push(newEntry);
}
degreesByCountry[index].degrees.push(degree);
});
return degreesByCountry;
}
thank's
You can group the array and map the object using Object.keys:
var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
var grouped = groupBy(array, "country");
var mappedArray = Object.keys(grouped).map(key => ( {name: key, degrees: grouped [key]} ));
And one more way:
arr = [ /* your array */ ];
arr = Object.values(arr.reduce((ac, el) => {
if(!ac[el.country]) ac[el.country] = {"name": el.country, "degrees": []}
ac[el.country].degrees.push(el);
return ac
}, {}))
console.log(arr) // formated
Another solution, which also handles 'id' => '#id' mapping:
const a = [{"name":"brevet","country":"fr"},{"name":"bac","country":"fr"},{"id":73,"name":"des","country":"ca"},{"name":"dep","country":"ca"},{"name":"other","country":"other"}];
const r = [...new Set(a.map(({country}) => country))] // list of unique country names
.map(c => Object.assign({name: c}, // for each country
{degrees: a.filter(x => x.country === c).map(y => Object.keys(y).includes('id') // handle 'id' => '#id' mutation
? {'#id': "/subscription_fields/" + y.id, name: y.name, country: y.country}
: y)
}))
console.log(r)
This is purely ES6, and quite terse, but possibly less readable. Also, it doesn't add the "#id": "/subscription_fields/83", which could be added as a post process:
const groupByKey = (arr, key) => [...arr.reduce((acc, deg) =>
acc.set(deg[key], {name: deg[key], degrees: [ ...(acc.get(deg[key]) || {degrees: []}).degrees, deg]})
, new Map()).values()];
console.log(groupByKey(degrees, 'country'));
You could use a hash table and collect all values in an object. For getting the result array, you need to push the object only once.
var data = [{ name: "brevet", country: "fr" }, { name: "bac", country: "fr" }, { id: 73, name: "des", country: "ca" }, { name: "dep", country: "ca" }, { name: "other", country: "other" }],
result = data.reduce(function (hash) {
return function (r, a) {
if (!hash[a.country]) {
hash[a.country] = { name: a.country, degrees: [] };
r.push(hash[a.country]);
}
hash[a.country].degrees.push({ name: a.name, country: a.country });
return r;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources