I have an array of objects that looks like below
var FinalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"}];
I am trying to loop through the array and return an array of items group by the key "name" which will hold indexes of the items with same key.
expected result like below:
[
{bene: [0,2]},
{leg: [1,3]},
{hello: [4]}
]
I've put together the below but can't get it to work.
var obj = FinalArray.reduce(function(agg, item, index, f) {
var name = item.name || ""
var index = FinalArray.findIndex(item)
/* var copy = [...item.jArray];
*/ if (!agg[name]) {
agg[name] = []
}
agg[name].push(index)
return agg;
}, {})
fairly new to using reduce and groupby. any help is appreciated. Thanks
You can generate an object of the names with their indexes with a reduce on the original array, just pushing indexes into the array for each name.
If you then want an array of those values (I'm not sure this is a better structure), you can use Object.entries to get the key value pairs and map those into individual objects in an array
var FinalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"}];
var obj = FinalArray.reduce((acc, { name }, i) => {
acc[name] = (acc[name] || []).concat([i])
return acc
}, {})
console.log(obj)
objArray = Object.entries(obj).map(([k, v]) => ({ [k] : v }))
console.log(objArray)
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can achieve this by just using two JavaScript methods Array.forEach() along with Object.keys().
Live Demo :
// Input array
var FinalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"}
];
const resObj = {};
const output = [];
// creating a object with the required key: values.
FinalArray.forEach((obj, index) => {
resObj[obj.name] ? resObj[obj.name].push(index) : resObj[obj.name] = [index];
});
// destructuring the object into an array of objects.
Object.keys(resObj).forEach(key => {
output.push({
[key]: resObj[key]
})
});
// final output
console.log(output);
The OP might try a combination of ...
a reduce based approach which straightforwardly creates and collects an index/map of name based groups where the group key resemble an iterated item's name key, and the group value is an array of same name-value item-indices.
and a mapping of the reduced object's entries.
const finalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
];
console.log(
'index/map based result ...',
finalArray
.reduce((groups, { name }, idx) => {
(groups[name] ??= []).push(idx);
return groups;
}, {})
);
console.log(
"OP's expected result ...",
Object
.entries(
finalArray
.reduce((groups, { name }, idx) => {
(groups[name] ??= []).push(idx);
return groups;
}, {})
)
.map(([key, value]) => ({ [ key ]: value }))
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Another approach was to solely stick to reduce, where one then needs to implement a reducer function which achieves everything in a single run and does both ...
keeping track of the (to be) generated groups and the (to be) collected indices
and aggregating the final result of the reduce method's accumulator/collector object which gets passed as the method's 2nd parameter ... its initialValue.
const finalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
];
const { result } = finalArray
.reduce(({ result = [], groups = {} }, { name }, idx) => {
let group = groups[name];
if (!group) {
group = groups[name] = { [ name ]: [] };
result.push(group);
}
group[name].push(idx)
return { result, groups };
}, { result: [] });
console.log({ result });
.as-console-wrapper { min-height: 100%!important; top: 0; }
i'm new here, i have problem that i can not solve.
I have 2 different arrays:
The first array - contains ratings of users with their ID name
[
{"handle":"frontend1", "_redis":"3", "_nodejs":"5", "_mysql":"2", "_python":"3", "_mongo":"4"},
{"handle":"frontend3", "_php":"4", "_mysql":"4", "_oracle":"4", "_ruby":"3", "_mongo":"5", "_python":"5"},
{"handle":"frontend4", "_java":"5", "_ruby":"5", "_mysql":"5", "_mongo":"5"}
]
The second set - contains the ratings, which I want to return to each user.
If there is a rating that is not in the second set, I will not return it
In the second set, values do not matter, only keys
[
"_assembler",
"_css",
"_python",
"_php"
]
I want to return to the first set, the handle, and all the rankings that exist in the second set.
[
{"handle":"frontend1", "_python":"3" },
{"handle":"frontend3", "_php":"4", "_python":"5" },
{"handle":"frontend4"}
]
this is what i try to do.
keys = [
"_assembler",
"_css",
"_python",
"_php"
]
source = [
{"handle":"frontend1", "_redis":"3", "_nodejs":"5", "_mysql":"2", "_python":"3", "_mongo":"4"},
{"handle":"frontend3", "_php":"4", "_mysql":"4", "_oracle":"4", "_ruby":"3", "_mongo":"5", "_python":"5"},
{"handle":"frontend4", "_java":"5", "_ruby":"5", "_mysql":"5", "_mongo":"5"}
];
result = [];
tmp = {};
source.forEach((item) => {
Object.keys(item).map(({key,value}) =>
{
if(key == "handle")
{
tmp[key]=value;
}
if(keys.includes(key))
{
tmp[key]=value;
}
})
result.push(...tmp);
tmp = {};
});
You can do this with a map utilizing a couple of other array methods such as filter, and Object methods.
const keys = [
"_assembler",
"_css",
"_python",
"_php"
]
const source = [
{"handle":"frontend1", "_redis":"3", "_nodejs":"5", "_mysql":"2", "_python":"3", "_mongo":"4"},
{"handle":"frontend3", "_php":"4", "_mysql":"4", "_oracle":"4", "_ruby":"3", "_mongo":"5", "_python":"5"},
{"handle":"frontend4", "_java":"5", "_ruby":"5", "_mysql":"5", "_mongo":"5"}
];
const result = source.map( s => ({
handle: s.handle,
...Object.fromEntries(Object.entries(s).filter(x => x[0] != "handle" && keys.includes(x[0])))
}));
console.log(result);
My below code is working fine and gives the correct desired output. But I am trying to use map, filter etc. instead of for loop. Lodash map and filter also works.
var arr = [
{"comp_id":1, desc: 'from comp1', updated: true},
{
"comp_id":2, desc: 'from comp2', updated: false}
];
var complaint_sources = [
{"comp_id":2,"consumer_source":"Hotline In","description_option":"English"},
{"comp_id":1,"consumer_source":"Online","description_option":"Other"},
{"comp_id":1,"consumer_source":"Email","description_option":null},
{"comp_id":2,"consumer_source":"Email","description_option":null}]
for(let i =0 ;i<arr.length;i++) {
let x=[];
for(let j=0;j<complaint_sources.length;j++){
if(arr[i].comp_id === complaint_sources[j].comp_id){
x.push(complaint_sources[j]);
arr[i].comp_src = x;
}
}
}
console.log(arr);
Basically I am looping through arr array and inside that looping through the complaint_sources array and when the comp_id matches I am modifying the arr array and adding a comp_src property to the object of arr array. This comp_src property will be an array of complaint_sources matched by comp_id.
this will work:
var arr = [
{"comp_id":1, desc: 'from comp1', updated: true},
{"comp_id":2, desc: 'from comp2', updated: false}
];
var complaint_sources = [
{"comp_id":2,"consumer_source":"Hotline In","description_option":"English"},
{"comp_id":1,"consumer_source":"Online","description_option":"Other"},
{"comp_id":1,"consumer_source":"Email","description_option":null},
{"comp_id":2,"consumer_source":"Email","description_option":null}
];
const grouped_sources = complaint_sources.reduce((acc, value) => {
(acc[value.comp_id] = acc[value.comp_id] || []).push(value);
return acc;
}, {})
const data = arr.map((comp) => ({
...comp,
comp_src: grouped_sources[comp.comp_id]
}));
console.log(data);
I'm trying to setup a Node.js API that sends JSON data to the client for use in an NVD3 chart. The chart accepts JSON input in the following format:
[
{
"key”:”KEY NAME“,
"values":[
[
1138683600000,
14.212410956029
],
[
1141102800000,
13.973193618249
]
]
},
{
"key”:”KEY NAME“,
"values":[
[
1138683600000,
7.1590087090398
],
[
1141102800000,
7.1297210970108
]
]
}
]
However, my Node program currently outputs JSON in this format:
[
{
"key”:”SAME KEY NAME”,
"values":[
1510148301000,
34
]
},
{
"key”:”SAME KEY NAME”,
"values":[
1509626301000,
55
]
},
{
"key”:”SAME KEY NAME“,
"values":[
1509539901000,
62
]
},
{
"key”:”DIFFERENT KEY NAME“,
"values":[
1509453501000,
58
]
}
]
I want to combine any "key" indices that are the same as other ones and merge the "values" with one another in the specified format. I searched all over to find a way to do this, but each method I came across didn't account for multiple pairings within the "value" index.
Any suggestions on how I could do this?
Thanks!
You can use Array.prototype.reduce to accumulate the items from your original array into an object keyed uniquely by the item's key-value. Since this leaves you with an Object instead of an array, you can then use Object.values to spit out the array of values like your example output.
let data = [
{"key":"A", "values":[1510148301000, 34]},
{"key":"A", "values":[1509626301000, 55]},
{"key":"A", "values":[1509539901000, 62]},
{"key":"B", "values":[1509453501000, 58]},
{"key":"B", "values":[1509453501001, 57]},
];
let combined = Object.values(data.reduce((accumulator, item) => {
if (!accumulator[item.key])
accumulator[item.key] = {key: item.key, values: []};
accumulator[item.key].values.push(item.values);
return accumulator;
}, {}));
console.log(combined);
I'm not sure about what you want (merge?), but it seems to be like that:
function combine (obj) {
var combined = {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (!!combined[key]) {
combined[key] = [].concat(combined[key], obj[key].values) // everything in one
// or
// combined[key].push(obj[key].values) // everything in distinct arrays
} else {
combined[key] = obj[key].values
// or
// combined[key] = [obj[key].values] // in distinct arrays
}
}
}
return combined
}
var original=[{"key":"SAME KEY NAME","values":[1510148301000,34]},{"key":"SAME KEY NAME","values":[1509626301000,55]},{"key":"SAME KEY NAME","values":[1509539901000,62]},{"key":"DIFFERENT KEY NAME","values":[1509453501000,58]}];
var result=[];
var isAlreadyAdded=false;
original.forEach(function(outerObj){
var newObj={};
var values=[];
original.forEach(function(element) {
if(newObj["key"] !== outerObj.key){
newObj["key"]=element.key;
values=[];
values.push(element["values"]);
}else if(outerObj.key ===element.key ){
values.push(element["values"]);
}
});
newObj["values"]=values;
var count=0;
result.push(newObj);
});
var temp=[];
result=result.filter((x, i)=> {
if (temp.indexOf(x.key) < 0) {
temp.push(x.key);
return true;
}
return false;
})
console.log(result);
I have an object as below:
obj = {
'fruita' : 'eat',
'fruitb' : 'eat',
'fruitc' : 'throw',
'fruitd' : 'throw'
}
output = {
'eat' : ['fruita','fruitb'],
'throw' : ['fruitc','fruitd']
}
How to apply _.groupBy in order to get the list of eat and throw fruits seperately?
We can turn our object to an array of key-value pairs:
var keyValues = Object.keys(obj).map(key => ({ key, value: obj[key] }));
And then we can perform a reduce to construct our object:
var values = keyValues.reduce((acc, kv) => {
if (typeof acc[kv.value] === 'undefined') {
acc[kv.value] = [];
}
acc[kv.value].push(kv.key);
return acc;
}, {});
No lodash necessary!
You could use a for..in loop to set properties of output object to values of obj , push obj properties to items within array at output
var obj = {
'fruita' : 'eat',
'fruitb' : 'eat',
'fruitc' : 'throw',
'fruitd' : 'throw'
}
var output = {};
for (var prop in obj) {
if (!output[obj[prop]]) {
output[obj[prop]] = [];
output[obj[prop]].push(prop)
} else {
output[obj[prop]].push(prop)
}
}
console.log(output)