Group or summarize Javascript array - javascript

var json =
[
{
id: 11,
name:"app1",
family:"apps",
caseID: 123,
order:1
},
{
id: 12,
name:"app1",
family:"apps",
caseID: 123,
order:2
},
{
id: 13,
name:"app1",
family:"apps",
caseID: 123,
order:3
},
{
id: 14,
name:"app2",
family:"tools",
caseID: 129,
order:1
},
{
id: 15,
name:"app2",
family:"tools",
caseID: 129,
order:2
},
{
id: 16,
name:"app3",
family:"utils",
caseID: 120,
order:1
},
{
id: 17,
name:"app3",
family:"utils",
caseID: 120,
order:2
},
id: 18,
name:"app3",
family:"utils",
caseID: 150,
order:null
}
]
Hello, I would like to sort the array above by the highest "order" key and return the filtered array below. The common key is the caseID. Also, If the order key is null return it.
I've searched and tested some functions and loops but cannot seem to get it rite. Any help will be much appreciated. I'd prefer es2015 if possible.
Thank you!
filtered =
[
{
id: 13,
name:"app1",
family:"apps",
caseID: 123,
order:3
},
{
id: 15,
name:"app2",
family:"tools",
caseID: 129,
order:2
},
{
id: 17,
name:"app3",
family:"utils",
caseID: 120,
order:2
},
{
id: 18,
name:"app3",
family:"utils",
caseID: 150,
order:null
}
]

I would start by getting rid of dupes. You can do this with reduce() and assigning to an object keyed to caseID. You can simultaneously avoid any object with a smaller order than one you've already seen. Then you can take the values of that hash which will be the unique objects base on caseID and sort them like you normally would. For example:
var json = [{ "id": 11, "name":"app1", "family":"apps", "caseID": 123, "order":1},{ "id": 12, "name":"app1", "family":"apps", "caseID": 123, "order":2},{ "id": 13, "name":"app1", "family":"apps", "caseID": 123, "order":3},{ "id": 14, "name":"app2", "family":"tools", "caseID": 129, "order":1},{ "id": 15, "name":"app2", "family":"tools", "caseID": 129, "order":2},{ "id": 16, "name":"app3", "family":"utils", "caseID": 120, "order":1},{ "id": 17, "name":"app3", "family":"utils", "caseID": 120, "order":2},{ "id": 18, "name":"app3", "family":"utils", "caseID": 150, "order":null},]
// get just the filtered items based on caseID
// picking out only the largest
let filtered = json.reduce((a,c) => {
if (!a[c.caseID] || a[c.caseID]['order'] < c.order) a[c.caseID] = c
return a
}, {})
// basic sort
let result = Object.values(filtered).sort((a,b) => b.order - a.order)
console.log(result)

You could use a caseID hashtable and override results you find later if order is higher:
const result = [], hash = {};
for(const el in json) {
const exists = hash[el.caseId];
if(exists) {
if(el.order > exists.order)
Object.assign(exists, el);
} else {
result.push(hash[el.caseId] = {...el});
}
}

You can try following
Method
Create an object with unique case ID as key and value being the item with highest order
Sort based on order
// Code goes here
var json = [{"id":11,"name":"app1","family":"apps","caseID":123,"order":1},{"id":12,"name":"app1","family":"apps","caseID":123,"order":2},{"id":13,"name":"app1","family":"apps","caseID":123,"order":3},{"id":14,"name":"app2","family":"tools","caseID":129,"order":1},{"id":15,"name":"app2","family":"tools","caseID":129,"order":2},{"id":16,"name":"app3","family":"utils","caseID":120,"order":1},{"id":17,"name":"app3","family":"utils","caseID":120,"order":2},{"id":18,"name":"app3","family":"utils","caseID":150,"order":null}];
var map = {};
// Create a map of unique case ID's with highest order
json.forEach((item) => {
if(map[item.caseID]) {
if(map[item.caseID].order < item.order) {
map[item.caseID] = item;
}
} else {
map[item.caseID] = item;
}
});
// Sorting the array based on order
var result = Object.values(map).sort((a,b) => b.order-a.order);
console.log(result);

In ES6:
json.sort((a, b) => a.caseID > b.caseID);
let bad_order = json.filter(v => v.order === null);
let good_order = json.filter(v => v.order !== null);
Example
In ES5:
json.sort(function(a, b) { return a.caseID > b.caseID; });
var bad_order = [];
var good_order = [];
for(var i = 0; i < json.length; i++){
if(json[i].order === null)
bad_order.push(json[i]);
else
good_order.push(json[i]);
}
Example

Use reduce method to create an object where the keys will be the caseID.While creating the object check if the value of the order is more or less that the current order value.If the current value is less the than the new value, replace it with new value.
Then use Object.values(object) to create an array of values from the object
var json = [{
"id": 11,
"name": "app1",
"family": "apps",
"caseID": 123,
"order": 1
},
{
"id": 12,
"name": "app1",
"family": "apps",
"caseID": 123,
"order": 2
},
{
"id": 13,
"name": "app1",
"family": "apps",
"caseID": 123,
"order": 3
},
{
"id": 14,
"name": "app2",
"family": "tools",
"caseID": 129,
"order": 1
},
{
"id": 15,
"name": "app2",
"family": "tools",
"caseID": 129,
"order": 2
},
{
"id": 16,
"name": "app3",
"family": "utils",
"caseID": 120,
"order": 1
},
{
"id": 17,
"name": "app3",
"family": "utils",
"caseID": 120,
"order": 2
}, {
"id": 18,
"name": "app3",
"family": "utils",
"caseID": 150,
"order": null
}
]
var m = json.reduce(function(acc, curr, index) {
if (acc[curr['caseID']] === undefined) {
acc[curr['caseID']] = curr;
} else {
if (acc[curr['caseID']].order < curr.order) {
acc[curr['caseID']] = curr;
}
}
return acc;
}, {})
console.log(Object.values(m))

This should help you filter array of objects.
var filteredMap = {};
json.forEach(function (item) {
filteredMap[item.caseID] = item;
});
var filteredArray = [];
for (var key in filteredMap) {
filteredArray.push(filteredMap[key]);
}
console.log(JSON.stringify(filteredArray));

Sort by order and caseID and then filter by caseID,Here is the code:
var json =
[
{
id: 11,
name:"app1",
family:"apps",
caseID: 123,
order:1
},
{
id: 12,
name:"app1",
family:"apps",
caseID: 123,
order:2
},
{
id: 13,
name:"app1",
family:"apps",
caseID: 123,
order:3
},
{
id: 14,
name:"app2",
family:"tools",
caseID: 129,
order:1
},
{
id: 15,
name:"app2",
family:"tools",
caseID: 129,
order:2
},
{
id: 16,
name:"app3",
family:"utils",
caseID: 120,
order:1
},
{
id: 17,
name:"app3",
family:"utils",
caseID: 120,
order:2
}, {
id: 18,
name:"app3",
family:"utils",
caseID: 150,
order:null
}
]
var obj = {}
var arr = json.sort(function(a, b) {
return b.order - a.order
}).sort(function(a, b) {
return a.caseId - b.caseId
}).filter(function(item, index, array){
return obj.hasOwnProperty(item.caseID) ? false : (obj[item.caseID] = true)
})
console.log(arr)
demo: http://jsbin.com/qabehorike/edit?js,console,output

Related

Merging multiple arrays inside an objects into a single array

My Object contains different datatypes including array. I want to concatenate all arrays(in a single array)
I have written using foreach and concat.
Is there any way I can have a better solution, or this is correct?
See the below snippet. concat array value3 and value5 into single array.
var Input = {
"value1": 10,
"value2": "abcd",
"value3": [
{
"v1": 100,
"v2": 89
},
{
"v1": 454,
"v2": 100
}
],
"value4": "xyz",
"value5": [
{
"v6": 1,
"v7": -8
},
{
"v1": 890,
"v2": 10
}
]
}
var OutputData = [];
let keys = Object.keys(Input);
keys.forEach(key => {
if (Array.isArray(Input[key])) {
try {
OutputData= OutputData.concat(Input[key])
} catch (error) {
}
}
});
console.log(OutputData)
You could use Array.prototype.filter() with Array.prototype.flat() method get a cleaner code. First get all the values using Object.values() method. Then use filter method to get the arrays and at last use flat method to get a new array with all sub-array elements concatenated.
const input = {
value1: 10,
value2: 'abcd',
value3: [
{
v1: 100,
v2: 89,
},
{
v1: 454,
v2: 100,
},
],
value4: 'xyz',
value5: [
{
v6: 1,
v7: -8,
},
{
v1: 890,
v2: 10,
},
],
};
const ret = Object.values(input)
.filter((x) => Array.isArray(x))
.flat();
console.log(ret);
I think this might be a little bit cleaner to read:
var input = {
"value1": 10,
"value2": "abcd",
"value3": [{
"v1": 100,
"v2": 89
},
{
"v1": 454,
"v2": 100
}
],
"value4": "xyz",
"value5": [{
"v6": 1,
"v7": -8
},
{
"v1": 890,
"v2": 10
}
]
};
let res = [];
for (let k in input) {
if (input.hasOwnProperty(k) && Array.isArray(input[k]))
input[k].forEach(x => res.push(x));
}
console.log(res);

Count sum of values in JSON array

Having an array like this:
const data = [
{
"name": "Dave",
"coins": 14,
"weapons": 2,
"otherItems": 3,
"color": "red"
},
{
"name": "Vanessa",
"coins": 18,
"weapons": 1,
"otherItems": 5,
"color": "blue"
},
{
"name": "Sharon",
"coins": 9,
"weapons": 5,
"otherItems": 1,
"color": "pink"
},
{
"name": "Walter",
"coins": 9,
"weapons": 2,
"otherItems": 4,
"color": "white"
}
]
How to count sum of coins, weapons and otherItems using ES6 features? (I'm not attached to this: any simple method would be good.)
data.reduce((first, last) => first + last) generates a chain of [object Object][object Object]s...
You have to process every field separately (note that when you don't specify second parameter for reduce it will take first array object as seed and start processing from the second one):
const data = [
{
"name": "Dave",
"coins": 14,
"weapons": 2,
"otherItems": 3,
"color": "red"
},
{
"name": "Vanessa",
"coins": 18,
"weapons": 1,
"otherItems": 5,
"color": "blue"
},
{
"name": "Sharon",
"coins": 9,
"weapons": 5,
"otherItems": 1,
"color": "pink"
},
{
"name": "Walter",
"coins": 9,
"weapons": 2,
"otherItems": 4,
"color": "white"
}
]
let result = data.reduce((a,c)=> ({
coins: a.coins + c.coins,
weapons: a.weapons + c.weapons,
otherItems: a.otherItems + c.otherItems })
)
console.log(result);
You could take an array of wanted keys for the sums and create an object for the sums and add the wanted values.
const
data = [{ name: "Dave", coins: 14, weapons: 2, otherItems: 3, color: "red" }, { name: "Vanessa", coins: 18, weapons: 1, otherItems: 5, color: "blue" }, { name: "Sharon", coins: 9, weapons: 5, otherItems: 1, color: "pink" }, { name: "Walter", coins: 9, weapons: 2, otherItems: 4, color: "white" }],
keys = ['coins', 'weapons', 'otherItems'],
sums = data.reduce(
(r, o) => (keys.forEach(k => r[k] += o[k]), r),
Object.fromEntries(keys.map(k => [k, 0]))
);
console.log(sums);
You can use Array.prototype.reduce for this.
To make it a little bit more flexible and dynamic, make a Set of keys you want to get a count of.
Then go through each key in the Set and if that key is in the obj, sum it up in an accumulator object in the reduce callback:
const data = [{"name":"Dave","coins":14,"weapons":2,"otherItems":3,"color":"red"},{"name":"Vanessa","coins":18,"weapons":1,"otherItems":5,"color":"blue"},{"name":"Sharon","coins":9,"weapons":5,"otherItems":1,"color":"pink"},{"name":"Walter","coins":9,"weapons":2,"otherItems":4,"color":"white"}]
//Keys to count
const keys = new Set(["coins", "weapons", "otherItems"]);
const count = data.reduce((acc, obj) => {
const objKeys = keys.forEach(key => {
if (obj.hasOwnProperty(key)) {
acc[key] = (acc[key] || 0) + obj[key];
}
});
return acc;
}, {});
console.log(count);
Your idea is right, you need to use reduce method. The problem is that you're summing two objects, not their properties. All you need to do is change the code to the following (to sum the coins):
data.reduce((first, last) => first.coins + last.coins, 0)
And following for weapons:
data.reduce((first, last) => first.weapons + last.weapons, 0)

Extract items from a json file with values in an array

I am trying to handle JSON arrays to extract key value pair from the keys available from user selection.
This is not real time json example...It is just a sample
Example of JSON
var personnel = [
{
id: 5,
name: "Luke Skywalker",
pilotingScore: 98,
shootingScore: 56,
isForceUser: true,
},
{
id: 82,
name: "Sabine Wren",
pilotingScore: 73,
shootingScore: 99,
isForceUser: false,
skills:{
'skill1':'vision',
'skill2':'strength'
}
},
{
id: 22,
name: "Zeb Orellios",
pilotingScore: 20,
shootingScore: 59,
isForceUser: false,
},
{
id: 15,
name: "Ezra Bridger",
pilotingScore: 43,
shootingScore: 67,
isForceUser: true,
skills:{
'skill1':'vision',
'skill2':'strength'
}
},
{
id: 11,
name: "Caleb Dume",
pilotingScore: 71,
shootingScore: 85,
isForceUser: true,
},
];
sample_arr = [id,name,skills.skill1];
let op = personnel.map(md => {
return { id: md.id,name:md.name,skills{skill1:md.skills.skill1}};
});
console.log(JSON.stringify(op,null,2))
I wanted to get key value pair like below.
[
{
"id": 5,
"name": "Luke Skywalker"
},
{
"id": 82,
"name": "Sabine Wren",
"skills":{
"skill1": 'vision'
}
},
{
"id": 22,
"name": "Zeb Orellios"
},
{
"id": 15,
"name": "Ezra Bridger"
},
{
"id": 11,
"name": "Caleb Dume"
}
]
I now updated the my problem statement.
Requirement:
Extract all JSON values selected by the user to a new array. This will save more time as the json is 700MB all the way and it is time consuming to handle on every request
You have the user selections stored in the array? If so, you could do something like:
let sample_arr = ['id', 'name']
let op = personnel.map(md => {
let user = {}
sample_arr.forEach(val => {
if (md[val]) {
user[val] = md[val]
}
})
return user
})
Here's a simple function to do this:
const project = (keys) => (xs) =>
xs .map (x => keys .reduce ( (a, k) => ({...a, [k]: x[k]}), {} ))
var personnel = [{id:5,name:"Luke Skywalker",pilotingScore:98,shootingScore:56,isForceUser:true},{id:82,name:"Sabine Wren",pilotingScore:73,shootingScore:99,isForceUser:false,skills:{skill1:"vision",skill2:"strength"}},{id:22,name:"Zeb Orellios",pilotingScore:20,shootingScore:59,isForceUser:false},{id:15,name:"Ezra Bridger",pilotingScore:43,shootingScore:67,isForceUser:true,skills:{skill1:"vision",skill2:"strength"}},{id:11,name:"Caleb Dume",pilotingScore:71,shootingScore:85,isForceUser:true}];
console .log (
project (['id', 'name']) (personnel)
)
The name project is from Codd's early papers on relational databases; it's similar in feel to SQL's select statement.
Update
The answer from KellyKapoor has one feature the above lacks: it only includes the property name if the data has it (so no skills: undefined.)
It's not clear which behavior the OP is looking for, but this minor modification offers that feature
const project2 = (keys) => (xs) =>
xs .map (x => keys .reduce ((a, k) => ({...a, ...(k in x ? {[k]: x[k]} : {}) }), {} ))
var personnel = [{id:5,name:"Luke Skywalker",pilotingScore:98,shootingScore:56,isForceUser:true},{id:82,name:"Sabine Wren",pilotingScore:73,shootingScore:99,isForceUser:false,skills:{skill1:"vision",skill2:"strength"}},{id:22,name:"Zeb Orellios",pilotingScore:20,shootingScore:59,isForceUser:false},{id:15,name:"Ezra Bridger",pilotingScore:43,shootingScore:67,isForceUser:true,skills:{skill1:"vision",skill2:"strength"}},{id:11,name:"Caleb Dume",pilotingScore:71,shootingScore:85,isForceUser:true}];
console .log (
project2 (['id', 'name', 'skills']) (personnel)
)
Whats the problem with this?
let op = personnel.map(md => {
return { id: md.id,name:md.name};
});
You can create a function which extracts the props from an object based on a passed array of keys:
var data = [ { id: 5, name: "Luke Skywalker", pilotingScore: 98, shootingScore: 56, isForceUser: true, }, { id: 82, name: "Sabine Wren", pilotingScore: 73, shootingScore: 99, isForceUser: false, skills:{ 'skill1':'vision', 'skill2':'strength' } }, { id: 22, name: "Zeb Orellios", pilotingScore: 20, shootingScore: 59, isForceUser: false, }, { id: 15, name: "Ezra Bridger", pilotingScore: 43, shootingScore: 67, isForceUser: true, skills:{ 'skill1':'vision', 'skill2':'strength' } }, { id: 11, name: "Caleb Dume", pilotingScore: 71, shootingScore: 85, isForceUser: true, }, ];
let pick = (obj, fields) => Object.keys(obj)
.reduce((r,c) => (fields.includes(c) ? r[c] = obj[c] : null, r), {})
let result = data.map(x => pick(x, ['id', 'name', 'skills']))
console.log(result)
Then all you need is to loop though via Array.map to pick from all objects.

recursively transform json object

I need help with recursively transform json object into another json object.
My input object looks like this:
var my_obj = {
"id": 22,
"eventTypeId": 37,
"eventTypeName": "CommonOnly",
"parentEvent": {
"id": 21,
"eventTypeId": 35,
"eventTypeName": "FullTest",
"parentEvent": {
"id": 20,
"parentEvent": null,
"eventTypeId": 38,
"eventTypeName": "FullTest"
}
},
"childrenEvents": [
{
"id": 24,
"parentEventId": 22,
"eventTypeId": 36,
"eventTypeName": "BlindedTest",
"childrenEvents": []
},
{
"id": 23,
"parentEventId": 22,
"eventTypeId": 38,
"eventTypeName": "OneCustom",
"childrenEvents": []
}
]
}
The output I want is:
var my_obj = {
"id": 20,
"eventTypeId": 38,
"parentEvent": null,
"eventTypeName": "FullTest",
"childrenEvents": [{
"id": 21,
"eventTypeId": 35,
"eventTypeName": "FullTest",
"childrenEvents": [
{
"id": 22,
"eventTypeId": 37,
"eventTypeName": "CommonOnly",
"childrenEvents": [
{
"id": 24,
"parentEventId": 22,
"eventTypeId": 36,
"eventTypeName": "BlindedTest",
"childrenEvents": []
}, {
"id": 23,
"parentEventId": 22,
"eventTypeId": 38,
"eventTypeName": "OneCustom",
"childrenEvents": []
}
]
}
]
}]
}
So I want to be able to get an object where the second parentEvent with parentEvent = null has became a root element, with an array childrenEvents, inside children array will be first parent event object with its own childrenEvents array and inside of this array I want to put existing root object with its own childrenEvents array
I appreciate if somebody could help me to resolve it. Thanks in advance.
My attempt
function rebuild(input)
{
var childrenEvents = [] ;
for ( f in input.parentEvent ) // we may have attributes other than "age"
if (f.parentEvent == null) {
f.parentEvent.push(childrenEvents);
}
else {
f.parentEvent.push(input.parentEvent[f]);
}
if (input.childrenEvents.length !== 0)
{
input.parentEvent[f].push(input.childrenEvents)
}
return input;
}
console.log(rebuild( $scope.myObj))
});
plunker
You could use an object to build all dependencies and take only the one with
parentEvent === null
as tree.
var my_obj = { "id": 22, "eventTypeId": 37, "eventTypeName": "CommonOnly", "parentEvent": { "id": 21, "eventTypeId": 35, "eventTypeName": "FullTest", "parentEvent": { "id": 20, "parentEvent": null, "eventTypeId": 38, "eventTypeName": "FullTest" } }, "childrenEvents": [{ "id": 24, "parentEventId": 22, "eventTypeId": 36, "eventTypeName": "BlindedTest", "childrenEvents": [] }, { "id": 23, "parentEventId": 22, "eventTypeId": 38, "eventTypeName": "OneCustom", "childrenEvents": [] }] },
tree = function (data, root) {
function iter(a) {
var parent;
if (a.childrenEvents && Array.isArray(a.childrenEvents)) {
a.childrenEvents.forEach(iter);
}
a.childrenEvents = o[a.id] && o[a.id].childrenEvents;
o[a.id] = a;
if (a.parentEvent === root) {
r = a;
} else {
if (a.parentEvent && 'id' in a.parentEvent) {
parent = a.parentEvent.id;
}
if ('parentEventId' in a) {
parent = a.parentEventId;
}
if (parent !== undefined) {
o[parent] = o[parent] || {};
o[parent].childrenEvents = o[parent].childrenEvents || [];
o[parent].childrenEvents.push(a);
}
}
if (a.parentEvent) {
iter(a.parentEvent);
delete a.parentEvent;
}
}
var r, o = {};
iter(data);
return r;
}(my_obj, null);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The title of your question says "recursively" but there is no recursion (that I can see) in your code. Yo need to call rebuild() from within rebuild()... recursively.
Maybe something closer to this (haven't run it)...
function rebuild(input) {
var rslt = input; // If it stays this way, we've reached the end of the line
var parent = inpt.parentEvent;
if (parent) {
parent.childrenEvents = [];
parent.childrenEvents.push(input);
inpt.parentEventId = parent.id;
rslt = rebuild(parent);
}
return rslt;
}

return array of object javascript

With this array:
var booksStudents = [
{
name: "David",
books: {
"fantasy": 23,
"action": 31,
"thriller" 21,
}
},
name: "Paul",
books: {
"fantasy": 17,
"action": 13,
"thriller" 23,
}
},
name: "Zoe",
books: {
"fantasy": 5,
"action": 7,
"thriller" 28,
}
}];
I would like to return an array of objects, each containing the name of a person and the sum of all their respective books.
I know how to use the reduce method on a simple array but I am stuck with this array of object.
I was thinking of using .map and .reduce but I did not find something interesting.
booksStudents = booksStudents.map(function(item){
var count = 0;
for(var key in item.books){
count+=item.books[key];
}
item.count = count;
return item;
})
use map and for..in to count the number.
Firstly there are few mistakes in your array of objects, Let me point them.
var booksStudents = [
{
name: "David",
books: {
"fantasy": 23,
"action": 31,
"thriller": 21, // : missing
}
},
{ // { missing
name: "Paul",
books: {
"fantasy": 17,
"action": 13,
"thriller": 23, // : missing
}
},
{ // { missing
name: "Zoe",
books: {
"fantasy": 5,
"action": 7,
"thriller": 28, // : missing
}
}];
So now after this is fixed the solution to get your end result is by using this code.
var newArray = [];
$.each(booksStudents,function(index,value){
var currObj = {};
currObj.name= this.name;
currObj.totalBooks = parseInt(this.books.fantasy) +parseInt(this.books.action)+parseInt(this.books.thriller) ;
newArray.push(currObj);
});
console.log(newArray);
Here is a Wroking Fiddle check console for output
The output is as below .

Categories