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 have this in my code:
let obj = {EdadBeneficiario1: '32', EdadBeneficiario2: '5'}
var years = [];
let i;
for (i= obj;i<=obj;i++)
{
years.push({ edad_beneficiario : i })
}
the output is
[
edad_beneficiario:{EdadBeneficiario1:"32", EdadBeneficiario2:"5"}
]
but what i want is this
[
{edad_beneficiario:"32"},
{edad_beneficiario:"5"}
]
what can i do?
EDIT
By the way, if i do this
years.push({ edad_beneficiario :obj.EdadBeneficiario1})
years.push({ edad_beneficiario :obj.EdadBeneficiario2})
the output what i want resolve but i want it to do it with a for loop. Please, Help.
The problem is that in the loop, you are setting i = obj, then i = {EdadBeneficiario1: '32', EdadBeneficiario2: '5'}. i must be a integer value to work with the for loop in this case. You can use Object.values method to transform obj values into an array and get it's data to use it in the for loop.
let obj = {EdadBeneficiario1: '32', EdadBeneficiario2: '5'}
var years = [];
let objValuesArray = Object.values(obj);
for (let i = 0; i < objValuesArray.length; i++) {
years.push({ edad_beneficiario : objValuesArray[i] })
}
Does this work for you? Use Object.values() and Array.map() to get the desired output.
let obj = {
EdadBeneficiario1: '32',
EdadBeneficiario2: '5'
}
const output = Object.values(obj).map(value => ({
edad_beneficiario: value
}));
console.log(output);
let obj = {EdadBeneficiario1: '32', EdadBeneficiario2: '5'}
var years = [];
Object.entries(obj).map(([key, value]) => {
years.push( {edad_beneficiario: value} )
}
)
console.log(years)
/*
Array [ {…}, {…} ]
0: Object { edad_beneficiario: "32" }
1: Object { edad_beneficiario: "5" }
*/
const myFunc = (obj) => {
const years = Object.keys(obj).map((c, i) => {
const values = Object.values(obj).map((b) => b);
return { edad_beneficiario: values[i] };
});
console.log(years);
};
you can actually make it a lot shorter but i just wanted you to know that you can access object keys as well .
I have a object like this:
{
"ABC":{"minValue":0,"maxValue":5},
"XYZ":{"minValue":0,"maxValue":5},
"PQR":{"minValue":0,"maxValue":5},
"overall":{"minValue":0,"maxValue":5}
}
I am trying to make a simple array like this
[
["type":"ABC","minValue":0,"maxValue":5],
["type":"XYZ","minValue":0,"maxValue":5],
["type":"PQR","minValue":0,"maxValue":5],
["type":"overall","minValue":0,"maxValue":5]
]
not getting idea how to get it.
Here is my attempt:
var s = scoreFilters; //my json object
var out = Object.keys(s).map(function(data){
console.log(data)
return [["type":data,"minValue":data.minValue,"maxValue":data.maxValue]];
});
Assuming you want an array of objects for your output, you can .map the Object.entries of your input:
const obj = {
"ABC":{"minValue":0,"maxValue":5},
"XYZ":{"minValue":0,"maxValue":5},
"PQR":{"minValue":0,"maxValue":5},
"overall":{"minValue":0,"maxValue":5}
};
const arr = Object.entries(obj).map(([type, { minValue, maxValue }]) => ({
type,
minValue,
maxValue
}));
console.log(arr);
You could use Object.entries, map and spread syntax like this:
let input = {"ABC":{"minValue":0,"maxValue":5},"XYZ":{"minValue":0,"maxValue":5},"PQR":{"minValue":0,"maxValue":5},"overall":{"minValue":0,"maxValue":5}}
let output = Object.entries(input).map(([type, values]) => ({ type, ...values}))
console.log(output)
You can use Object.entries() and .map() to get an array of objects:
const data = {
"ABC": {"minValue": 0,"maxValue": 5},
"XYZ": {"minValue": 0,"maxValue": 5},
"PQR": {"minValue": 0,"maxValue": 5},
"overall": {"minValue": 0,"maxValue": 5}
};
const result = Object.entries(data)
.map(([ k, v ]) => Object.assign({}, {type: k}, v));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Say I have an array of objects that looks like this
let myArray = [
{item1: true},
{item2: false},
{item3: true},
{item4: false}
]
How would I iterate though this to return a new array of true values that looks like this:
let newArray = ['item1', 'item3']
I found this function but it only returns single items:
function findKey(map, term) {
var found = [];
for(var property in map) {
if(map.hasOwnProperty(property)) {
for(var key in map[property]) {
if(map[property].hasOwnProperty(key) && key === term) {
found.push(property);
}
}
}
}
return found;
}
Assuming myArray always contains objects with only 1 property.
let newArray = myArray
.map(item => Object.entries(item)[0])
.filter(([key, value]) => value)
.map(([key, value]) => key)
You could access the first key of each array item via Object.keys(), and use this to filter items with a true value for that first key, and then complete the process with a call to map() to transform the item to a value based on the same "first key" technique:
let myArray = [
{item1: true},
{item2: false},
{item3: true},
{item4: false}
]
let result = myArray
.filter(item => item[ Object.keys(item)[0] ] === true)
.map(item => Object.keys(item)[0])
console.log(result)
Use the function reduce to build the desired output. The handler of the function reduce will get the keys and check for each value === true.
This approach checks for the whole set of keys within an object. Further, this way you only use one loop.
let myArray = [{item1: true},{item2: false},{item3: true},{item4: false}],
result = myArray.reduce((a, c) => a.concat(Object.keys(c).filter(k => c[k] === true)), []);
console.log(result);
Something much optimized than the accepted answer would look like this:
const arr = [
{ item1: true },
{ item2: false },
{ item3: true },
{ item4: false }
]
const result = [];
const len = arr.length;
for (let i = 0; i < len; ++i) {
const obj = arr[i];
const key = Object.keys(obj)[0];
if(obj[key]) {
result.push(key);
}
}
console.log(result);
There is only one loop over the array, instead of map and filter which ends up looping twice.
Shortest
let newArray = myArray.map( x=>Object.keys(x)[0] ).filter( (k,i)=>myArray[i][k] );
In above solution first we use: map which works as for-loop to get array of keys (using Object.keys) ["item1", "item2", "item3", "item4"]. Then we filter that array by choose only those keys for which original array object has true. e.g myArray[0]["item1"] -> true (we use fact that filter funtion takes array element (k) and its index (i) which is the same for elements in myArray). In map and filter we use arrow functions.
I have 2 objects array as follows:
arr1 = [ { 'v1': 'abcde',
'pv_45': 13018,
'geolocation': '17.340291,76.842807'
}]
arr2 =[{ 'v1':'abcde',
'pv_50': 13010,
geolocation: '17.340291,76.842807'
}]
I want to merge the above 2 array int0 single based on condition that 'v1' and 'geolocation' should be same as follows:
[{'v1':'abcde',
'pv_45': 13018,
'pv_50': 13010,
'geolocation': '17.340291,76.842807'}]
I used _.extend, but its not checking any condition blindly it will merge. Please share your ideas. Thanks in advance.
you can use underscore js union and uniq to do that.
var mergedArray = _.uniq(_.union(c1, c2), false, function(item, key, a){ return item; });
Using pure JavaScript it could be done like this:
var arr1 = [ { 'v1': 'abcde',
'pv_45': 13018,
'geolocation': '17.340291,76.842807'
}],
arr2 =[{ 'v1':'abcde',
'pv_50': 13010,
geolocation: '17.340291,76.842807'
}],
mergeOnV1Geo = function (arr1, arr2) {
var mergeObj = {},
merge = function (item) {
var key = item.v1 + ',' + item.geolocation;
// if this is the first object with this key
// create a new object and copy v1, geolocation info
if (!mergeObj[key]) {
mergeObj[key] = {
v1: item.v1,
geolocation: item.geolocation
};
}
// add other props
Object.keys(item).forEach(function (prop) {
if (!prop.match(/v1|geolocation/)) {
mergeObj[key][prop] = item[prop];
}
});
};
arr1.forEach(merge);
arr2.forEach(merge);
// map back into an array
return Object.keys(mergeObj).map(function (key) {
return mergeObj[key];
});
};
mergeOnV1Geo(arr1, arr2);
You could do the following:
var arr3 = [].concat.apply([], arr1, arr2);
var temp =_.groupBy(arr3, 'geolocation');
var result = Object.keys(_.groupBy(arr3, 'geolocation')).map(function(x) { return _.extend.apply(0, p[x]); })
if you prefer ES-6 arrow functions the result becomes
Object.keys(_.groupBy(arr3, 'geolocation')).map((x) => _.extend.apply(0, p[x]);)
ES6: Using spread operator and reduce.
arr1 = [{ v1: 'abcde',
pv_45: 13018,
geolocation: '17.340291,76.842807'
}]
arr2 =[{ v1:'abcde',
pv_50: 13010,
geolocation: '17.340291,76.842807'
}]
// Keys to be grouped i.e whose values should be equal
groupableKeys = ['v1', 'geolocation'];
// Reducer that creates an Object with Key as the
// groupable key values value1::value2 and Value as
// the list of objects whose v1 and geolocation are same
groupableReducer = (a, b) => {
const uniqKey = groupableKeys.map(key => b[key]).join("::");
a[uniqKey] = [...(a[uniqKey] || []), b];
return a;
}
// Merges two objects using the spread operator
mergableReducer = (a, b) => ({...a, ...b})
// Merge two arrays and start processing
groupableKeyObject = [...arr1, ...arr2].reduce(groupableReducer, {})
output = Object.keys(groupableKeyObject)
.map(key =>
groupableKeyObject[key].reduce(mergableReducer, {})
)
console.log(output);