Creating a new object from array of objects and grouping by specific matching key/value - javascript

Example of the object data I am dealing with
var myData = [{
"name": "John",
"age": 30,
"interest": "Baseball"
},
{
"name": "Bob",
"age": 21,
"interest": "Baseball"
},
{
"name" : "Sally",
"age" : 29,
"interest": "Tennis"
}]
I am trying to figure out the easiest way to group them by interests. I am open to using lodash or underscore, but I cannot get the final result to look like this....
I want this to be the output:
[{ "Baseball" : [{
"name": "John",
"age" : 30
},
{
"name" : "Bob",
"age" : 21
}]
},
{ "Tennis" : [{
"name" : "Sally",
"age" : 21
}]
}];
Basically, each interest becomes a new object key containing all of the matched values within arrays.
I am having trouble constructing this output. Any assistance would be greatly appreciated. I prefer to use lodash/underscore to keep things very easy.
Thank you!

You could use Array.reduce for this:
var myData = [
{
"name": "John",
"age": 30,
"interest": "Baseball"
},
{
"name": "Bob",
"age": 21,
"interest": "Baseball"
},
{
"name" : "Sally",
"age" : 29,
"interest": "Tennis"
}];
var result = myData.reduce(function(entities, obj) {
entities[obj.interest] = (entities[obj.interest] || []).concat({
name: obj.name,
age: obj.age
});
return entities;
}, {});
console.log(result);
A little bit more general approach:
function groupBy(data, key, tFunc) {
mapFunc = (typeof tFunc === "function")? tFunc: function(o) { return o };
return (Array.isArray(data)?data:[]).reduce(function(entities, o) {
if(o[key]) {
entities[o[key]] = (entities[o[key]] || []).concat(tFunc(o));
}
return entities;
}, {});
}
// test code
var myData = [
{
"name": "John",
"age": 30,
"interest": "Baseball"
},
{
"name": "Bob",
"age": 21,
"interest": "Baseball"
},
{
"name" : "Sally",
"age" : 29,
"interest": "Tennis"
}];
var result = groupBy(myData, "interest", function(o) { return { name: o.name, age: o.age}});
console.log(result);
var result2 = groupBy(myData, "age", function(o) { return o.name});
console.log(result2);

A group-by operation can be done by matching values in a dictionary (hashtable). In JavaScript all objects are dictionaries with property-names as the keys, for values we use arrays.
For example (press the "Run code snippet" button below to see the results):
function groupBy( input, propertyName ) {
var output = {};
for(var i = 0; i < input.length; i++) {
var groupByValue = input[i][propertyName];
if( !(groupByValue in output) ) {
output[ groupByValue ] = [];
}
var dolly = cloneObjectButIgnoreProperty( input[i], propertyName );
output[ groupByValue ].push( dolly );
}
return output;
}
function cloneObjectButIgnoreProperty( value, ignorePropertyName ) {
var dolly = {};
var propertyNames = Object.keys( value );
for( var i = 0; i < propertyNames .length; i++ ) {
var propertyName = propertyNames[i];
if( propertyName == ignorePropertyName ) continue;
dolly[propertyName ] = value[propertyName ];
}
return dolly;
}
var myData = [
{
"name": "John",
"age": 30,
"interest": "Baseball"
},
{
"name": "Bob",
"age": 21,
"interest": "Baseball"
},
{
"name" : "Sally",
"age" : 29,
"interest": "Tennis"
}
];
var groupedByInterest = groupBy( myData, 'interest' );
console.log( "By interest:" );
console.log( groupedByInterest );
var groupedByName = groupBy( myData, 'name' );
console.log( "By name:" );
console.log( groupedByName );
var groupedByAge = groupBy( myData, 'age' );
console.log( "By age:" );
console.log( groupedByAge );

The solution using Array.prototype.reduce() function:
var myData = [{ "name": "John", "age": 30, "interest": "Baseball" }, { "name": "Bob", "age": 21, "interest": "Baseball" }, { "name" : "Sally", "age" : 29, "interest": "Tennis" }],
result = myData.reduce(function (r, o) {
r[o.interest] = r[o.interest] || [];
r[o.interest].push({name: o.name, age: o.age});
return r;
}, {});
console.log(result);

var myData = [{name:"John",age:30,interest:"Baseball"},{name:"Bob",age:21,interest:"Baseball"},{name:"Sally",age:29,interest:"Tennis"}],
result = [],
interests = [...new Set(myData.map(v => v.interest))];
interests.forEach(v => result.push({ [v] : [] }));
myData.forEach((v,i) => result.forEach((c,i) => Object.keys(c)[0] == v.interest ? result[i][v.interest].push({name: v.name, age: v.age}) : c))
console.log(result);

Related

Sorting array is not happening

I have an array like this and I wnat to ignore first two object and then sort the based on its ISD code in ascdeing order.
My data
"Output" :
[{
Name:"Country"
},{
Name :"CODE"
},
{
"Name" : "Alex",
"Country" :"India",
"CODE": "91"
},{
"Name" : "David",
"Country" : "USA",
"CODE": "1"
},{
"Name" :"Ravi",
"Country" : "NZ"
"CODE": "61"
},{
"Name" :"Smith",
"Country" : "AUS"
"CODE": "64"
}
]
What I am trying here is
var sortedData = sortByKey(output,"CODE")
function sortByKey(array, key) {
return array.sort(function(a, b) {
var x = a[key]; var y = b[key];
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
}
But it is rearranging the data rendomly. CAn anyone help me what is going wrong here.
You coudld take localeCompare with some options for sorting numerical values in the right order.
function sortByKey(array, key) {
var temp = array.slice(2);
temp.sort(function (a, b) {
return (a[key] || '').localeCompare(b[key] || '', undefined, { numeric: true, sensitivity: 'base' });
});
return array.slice(0, 2).concat(temp);
}
var array = [{ Name: "Country" }, { Name: "CODE" }, { Name: "Alex", Country: "India", CODE: "2" }, { Name: "David", Country: "USA", CODE: "1" }, { Name: "Ravi", Country: "NZ", CODE: "11" }, { Name: "Smith", Country: "AUS", CODE: "24" }];
console.log(sortByKey(array, "CODE"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is working perfectly. If you are looking for numeric sort use parseFloat
If you don't need the data with CODE key use below method
`
var JSON = {
"Output": [
{Name: "Country"},
{Name: "CODE"},
{"Name": "Alex","Country": "India","CODE": "91"},
{"Name": "David","Country": "USA","CODE": "1"},
{"Name": "Ravi","Country": "NZ","CODE": "61"},
{"Name": "Smith","Country": "AUS","CODE": "64"}]
}
var sortedJSON = sortByKey(JSON.Output, "CODE");
console.log(sortedJSON);
function sortByKey(array, key) {
for (var obj in array) {
if(array[obj][key] === undefined) {
delete array[obj];
}
}
return array.sort(function (a, b) {
if(a[key] && b[key]){
var x = parseInt(a[key]);
var y = parseInt(b[key]);
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}
});
}
If you want to keep the objects without code use the one below
var JSON = {
"Output": [
{Name: "Country"},
{Name: "CODE"},
{"Name": "Alex","Country": "India","CODE": "91"},
{"Name": "David","Country": "USA","CODE": "1"},
{"Name": "Ravi","Country": "NZ","CODE": "61"},
{"Name": "Smith","Country": "AUS","CODE": "64"}]
}
var sortedJSON = sortByKey(JSON.Output, "CODE");
console.log(sortedJSON);
function sortByKey(array, key) {
return array.sort(function (a, b) {
if(a[key] && b[key]){
var x = parseInt(a[key]);
var y = parseInt(b[key]);
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}
});
}
This should works, hope it helps!
var data = [
{ "Name": "Country" },
{ "Name": "CODE" },
{ "Name": "Alex", "Country": "India", "CODE": "91" },
{ "Name": "David", "Country": "USA", "CODE": "1" },
{ "Name": "Ravi", "Country": "NZ", "CODE": "61" },
{ "Name": "Smith", "Country": "AUS", "CODE": "64" }
];
var sortedJSON = sortByKey(data, "CODE");
function sortByKey(array, key) {
var others = [], result;
result = array.filter(function(o) {
if (!o[key]) others.push(o);
return (o[key]);
}).sort(function(a, b) {
var x = a[key], y = b[key];
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
return others.concat(result);
}
console.log(sortedJSON);

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; }

Create arrays from JavaScript objects

I have some data which looks like this:
{
"obj":
[
{
"name": "name1",
"age": "24"
},
{
"name": "name2",
"age": "17"
}
]
}
What I need to do is to create 2 arrays from it.
For example:
namelist[];
agelist[];
so the result would be:
namelist: ['name1', 'name2'];
agelist: [24, 17];
My question is, how can I do this?
var namelist = [];
var agelist = [];
for(var i in obj.obj){
namelist.push(obj.obj[i].name);
agelist.push(obj.obj[i].age);
}
console.log(namelist, agelist);
Is this what U wanted ?
var zz={
"obj": [
{
"name": "name1",
"age": "24"
},
{
"name": "name2",
"age": "17"
}
]
}
namelist=[];
agelist=[];
zz.obj.forEach(function(rec){
namelist.push(rec.name);
agelist.push(rec.age);
})
console.log(namelist,agelist)
You could use this ES6 code, and use the unitary plus for getting the ages as numbers. Assuming your object is stored in variable data:
var namelist = data.obj.map( o => o.name );
var agelist = data.obj.map( o => +o.age );
var data = {
"obj": [
{
"name": "name1",
"age": "24"
},
{
"name": "name2",
"age": "17"
}
]
};
var namelist = data.obj.map( o => o.name );
var agelist = data.obj.map( o => +o.age );
console.log(namelist);
console.log(agelist);
var arr = $.map(myObj, function(value, index) {
return [value];
});
console.log(arr);
if you are not using Jquery then:
var arr = Object.keys(myObj).map(function (key)
{ return obj[key];
});`
Make use of jquery map function or otherwise you can loop over the object and push it into array using javascript for loop and use the push() function. Refer Loop through an array in JavaScript
Jquery
var data = {
"obj": [
{
"name": "name1",
"age": "24"
},
{
"name": "name2",
"age": "17"
}
]
}
var name = $.map(data.obj, function(value, index) {
return value.name;
});
var age = $.map(data.obj, function(value, index) {
return value.age;
});
console.log(name);
console.log(age);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Javascript
var data = {
"obj": [
{
"name": "name1",
"age": "24"
},
{
"name": "name2",
"age": "17"
}
]
}
var names = [], ages=[];
data.obj.forEach(function(value, index) {
names.push(value.name);
ages.push(value.age);
});
console.log(names,ages);

how to count similar value object in json?

I have this JSON structure:
[{
"name": "ankit",
"DOB": "23/06"
}, {
"name": "kapil",
"DOB": "26/06"
}, {
"name": "ankit",
"DOB": "27/06"
}]
I want to count similar object with value ankit. How can I do this?
You can use Array.prototype.filter():
var count = json.filter(function (el) {
return el.name == 'ankit';
}).length;
How about:
let a = [
{ "name": "ankit", "DOB": "23/06" },
{ "name": "kapil", "DOB": "26/06" },
{ "name": "ankit", "DOB": "27/06" }
];
let count = 0;
a.forEach(item => {
if (item.name === "ankit") {
count++;
}
});
(code in playground)
You could use an object for counting and get the wanted count for a name with the name as property.
var data = [{ "name": "ankit", "DOB": "23/06" }, { "name": "kapil", "DOB": "26/06" }, { "name": "ankit", "DOB": "27/06" }],
count = {};
data.forEach(function (a) {
count[a.name] = (count[a.name] || 0) + 1;
});
console.log(count);
console.log(count['ankit']);
You can use the reduce method to reduce the items that have the name ankit to a number.
var items = [
{
name: 'ankit',
DOB: '23/06'
},
{
name: 'kapil',
DOB: '26/06'
},
{
name: 'ankit',
DOB: '27/06'
}
]
var numItems = items.reduce(function (count, item) {
return item.name === 'ankit' ? count + 1 : count
}, 0)
document.write('Number of items with the name `ankit`: ' + numItems)
1. Get the object from JSON:
var obj = JSON.parse(text);
2. Get your array filtered:
var count = obj.filter(function(obj) { return obj.name == "ankit" }).length;

How to transform JavaScript hashmap?

i'm trying to create a <String, Array()> map from a json object.
Imagine i got this json structure:
[
{
"userId": "123123",
"password": "fafafa",
"age": "21"
},
{
"userId": "321321",
"password": "nana123",
"age": "34"
}
]
The map i want to create would be:
key (string), value (array)
{
"userId": [
"123123",
"321321"
],
"password": [
"fafafa",
"nana123"
],
"age": [
"21",
"34"
]
}
Is it possible to do this? :/
Thanks in advance.
Demo
var json = '[{"userId" : "123123", "password": "fafafa", "age": "21"}, {"userId" : "321321", "password" : "nana123", "age" : "34"}]';
var list = JSON.parse(json);
var output = {};
for(var i=0; i<list.length; i++)
{
for(var key in list[i])
{
if(list[i].hasOwnProperty(key))
{
if(typeof output[key] == 'undefined')
{
output[key] = [];
}
output[key].push(list[i][key]);
}
}
}
document.write(JSON.stringify(output));
Outputs:
{"userId":["123123","321321"],"password":["fafafa","nana123"],"age":["21","34"]}
function mergeAttributes(arr) {
return arr.reduce(function(memo, obj) { // For each object in the input array.
Object.keys(obj).forEach(function(key) { // For each key in the object.
if (!(key in memo)) { memo[key] = []; } // Create an array the first time.
memo[key].push(obj[key]); // Add this property to the reduced object.
});
return memo;
}, {});
}
var json = '[{"userId" : "123123", "password": "fafafa", "age": "21"}, {"userId" : "321321", "password" : "nana123", "age" : "34"}]';
mergeAttributes(JSON.parse(json));
// {
// "userId": ["123123", "321321"],
// "password": ["fafafa", "nana123"],
// "age": ["21", "34"]
// }
Javascript's JSON.stringify will help you to convert any JSON compliant object model into a JSON string.

Categories

Resources