Javascript sum of items in a complex object - javascript

I have some data that I'm counting and putting the totals into an array.
Here is the data and code:
var data = {
"cars": [
{
"id": "1",
"name": "name 1",
"thsub": [
{
"id": "11",
"name": "sub 1",
"stats": {
"items": 5,
},
"ions": null
},
{
"id": "22",
"name": "sub 2",
"stats": {
"items": 5,
},
"translations": null
}
],
"image": null
},
{
"id": "2",
"name": "name 2",
"thsub": [
{
"id": "33",
"name": "sub 43",
"stats": {
"items": 20,
},
"ions": null
},
{
"id": "44",
"name": "sub 76",
"stats": {
"items": 5,
},
"translations": null
}
],
"image": null
}
]
}
var thCount = [];
for(key in data.cars[0].thsub ){
if(data.cars[0].thsub[key].stats){
thCount.push(data.cars[0].thsub[key].stats.items);
}
}
console.log(thCount);
For some reason "thCount" is returning [5, 5] when the result should be: [10, 25]
where is the code going wrong?

The correct code for your problem is as pasted below:
**var count = [];
for(var i = 0; i < data.cars.length; i++){
countSum = 0;
for(key in data.cars[i].thsub){
countSum = countSum + data.cars[i].thsub[key].stats.items;
}
count.push(countSum);
}**
Try this code, will solve your problem.

You need another loop on cars.
var data = {
"cars": [{
"id": "1",
"name": "name 1",
"thsub": [{
"id": "11",
"name": "sub 1",
"stats": {
"items": 5,
},
"ions": null
}, {
"id": "22",
"name": "sub 2",
"stats": {
"items": 5,
},
"translations": null
}],
"image": null
},
{
"id": "2",
"name": "name 2",
"thsub": [{
"id": "33",
"name": "sub 43",
"stats": {
"items": 20,
},
"ions": null
}, {
"id": "44",
"name": "sub 76",
"stats": {
"items": 5,
},
"translations": null
}],
"image": null
}
]
}
var thCount = [];
for (var l = 0, m = data.cars.length; l < m; l++) {
thCount[l] = 0;
for (var i = 0, j = data.cars[l].thsub.length; i < j; i++) {
if (data.cars[l].thsub[i].stats) {
thCount[l]+=data.cars[l].thsub[i].stats.items;
}
}
}
console.log(thCount);

You should use reduce() and map() methods.Any of this using a callback function.
The reduce() method applies a function against an accumulator and each
value of the array (from left-to-right) to reduce it to a single
value.
The map() method creates a new array with the results of calling a
provided function on every element in this array.
var result=data.cars.map(function(item){
return item.thsub.reduce(function(a, b) { return a.stats.items + b.stats.items; });
});
var data = {
"cars": [
{
"id": "1",
"name": "name 1",
"thsub": [
{
"id": "11",
"name": "sub 1",
"stats": {
"items": 5,
},
"ions": null
},
{
"id": "22",
"name": "sub 2",
"stats": {
"items": 5,
},
"translations": null
}
],
"image": null
},
{
"id": "2",
"name": "name 2",
"thsub": [
{
"id": "33",
"name": "sub 43",
"stats": {
"items": 20,
},
"ions": null
},
{
"id": "44",
"name": "sub 76",
"stats": {
"items": 5,
},
"translations": null
}
],
"image": null
}
]
}
console.log(data.cars.map(function(item){
return item.thsub.reduce(function(a, b) { return a.stats.items + b.stats.items; });
}));

Related

angular 3 nested object

Can someone help me regarding my code I already search but had no luck on logic.
i am trying to get a nested drop but i get the same result on 3-child hierarchy.
this is the data from my API.
{
"data": [
{
"id": "1",
"name": "Metro Manila",
"parent": null
},
{
"id": "101",
"name": "Manila",
"parent": "1"
},
{
"id": "10101",
"name": "Malate",
"parent": "101"
},
{
"id": "10102",
"name": "Ermita",
"parent": "101"
},
{
"id": "10103",
"name": "Binondo",
"parent": "101"
},
{
"id": "102",
"name": "Makati",
"parent": "1"
},
{
"id": "10201",
"name": "Poblacion",
"parent": "102"
},
{
"id": "10202",
"name": "Bel-Air",
"parent": "102"
},
{
"id": "10203",
"name": "San Lorenzo",
"parent": "102"
},
{
"id": "10204",
"name": "Urdaneta",
"parent": "102"
},
{
"id": "103",
"name": "Marikina",
"parent": "1"
},
{
"id": "10301",
"name": "Sto Nino",
"parent": "103"
},
{
"id": "10302",
"name": "Malanday",
"parent": "103"
},
{
"id": "10303",
"name": "Concepcion I",
"parent": "103"
},
{
"id": "2",
"name": "CALABARZON",
"parent": null
},
{
"id": "201",
"name": "Laguna",
"parent": "2"
},
{
"id": "20101",
"name": "Calamba",
"parent": "201"
},
{
"id": "20102",
"name": "Sta. Rosa",
"parent": "201"
},
{
"id": "202",
"name": "Cavite",
"parent": "2"
},
{
"id": "20201",
"name": "Kawit",
"parent": "202"
},
{
"id": "203",
"name": "Batangas",
"parent": "2"
},
{
"id": "20301",
"name": "Lipa",
"parent": "203"
},
{
"id": "20302",
"name": "Tanauan",
"parent": "203"
},
{
"id": "3",
"name": "Central Luzon",
"parent": null
},
{
"id": "301",
"name": "Bulacan",
"parent": "3"
},
{
"id": "302",
"name": "Nueva Ecija",
"parent": "3"
},
{
"id": "303",
"name": "Tarlac",
"parent": "3"
},
{
"id": "304",
"name": "Pampanga",
"parent": "3"
}
]
}
this.data = result.body.data;
let parents = this.data.filter(x => x.parent == null);
let child_id = [];
let child_id2 = [];
for (let i = 0; i < parents.length; i++) {
let _myTreelist = new ParentData();
_myTreelist.data.parent = parents[i].name;
child_id = this.data.filter(x => x.parent == parents[i].id); //get child-1 with id
_myTreelist.data.child.child1 = child_id.map((item) => {
return item.name
})
for (let e = 0; e < child_id.length; e++) { //10 ids
child_id2 = this.data.filter(a => a.parent === child_id[e].id); //get child-2 with id
_myTreelist.data.child.child.child2 = child_id2.map((item) => {
return item.name
})
}
this.parentList.push(_myTreelist);
}
this is the image output I get.
it works the first and 2nd nested but in the 3rd it display same
make a recursive function
getChild(element:any,data:any[])
{
element.children=data.filter((x:any)=>x.parent==element.id)
if (element.children.length)
element.children.forEach((x:any)=>this.getChild(x,data))
else
element.children=null;
return element
}
then
treeData=this.data.filter(x=>!x.parent)
.map(x=>this.getChild(x,this.data))
stackblitz
If you use an API and an observable use pipe map
treeData$=this.service.getData().pipe(
map((data:any[])=>{
return data.filter(x=>!x.parent).map(x=>this.getChild(x,data))
})
)

Using angularjs forEach loops

I am getting this type of json in my $scope of angularjs:
$scope.someStuff = {
"id": 2,
"service": "bike",
"min": "22",
"per": "100",
"tax": "1",
"categoryservices": [
{
"id": 32,
"category": {
"id": 1,
"name": "software"
}
},
{
"id": 33,
"category": {
"id": 2,
"name": "hardware"
}
},
{
"id": 34,
"category": {
"id": 3,
"name": "waterwash"
}
}
]
}
I want to use angularjs forEach loop and i want to get only category name,
My expected output:
[{"name":"software"}, {"name":"hardware"}, {"name":"waterwash"}]
You can use Array.map()
The map() method creates a new array with the results of calling a provided function on every element in the calling array.
$scope.someStuff.categoryservices.map((x) => { return { name: x.category.name}})
var obj = {
"id": 2,
"service": "bike",
"min": "22",
"per": "100",
"tax": "1",
"categoryservices": [{
"id": 32,
"category": {
"id": 1,
"name": "software"
}
},
{
"id": 33,
"category": {
"id": 2,
"name": "hardware"
}
},
{
"id": 34,
"category": {
"id": 3,
"name": "waterwash"
}
}
]
};
console.log(obj.categoryservices.map((x) => {
return {
name: x.category.name
}
}))
You can use map method by passing a callback function as parameter.
const someStuff = { "id": 2, "service": "bike", "min": "22", "per": "100", "tax": "1", "categoryservices": [ { "id": 32, "category": { "id": 1, "name": "software" } }, { "id": 33, "category": { "id": 2, "name": "hardware" } }, { "id": 34, "category": { "id": 3, "name": "waterwash" } } ] }
let array = someStuff.categoryservices.map(function({category}){
return {'name' : category.name}
});
console.log(array);

Build a map using values of multiple objects in an array javascript

I need to build a map "A" from an existing array of objects. However the key value pairs on Map A are from the values of existing Object keys "id" and "cap".
Is it possible to read the values of 2 keys and store as an object
var items = [{
"id": 1,
"name": "Primary",
"cap": [{
"id": "1",
"name": "1s"
}, {
"id": "2",
"name": "T2s"
}]
},{
"id": 2,
"name": "Secondary",
"cap": [{
"id": "1",
"name": "1s"
}, {
"id": "2",
"name": "T2s"
}
]
}]
My map needs to be like this
{ "1" : [{
"id": "1",
"name": "1s"
}, {
"id": "2",
"name": "T2s"
}],
"2" : [{
"id": "1",
"name": "1s"
}, {
"id": "2",
"name": "T2s"
}]
}
Use Array#reduce to achieve the results like below:
var items = [{
"id": 1,
"name": "Primary",
"cap": [{
"id": "1",
"name": "1s"
}, {
"id": "2",
"name": "T2s"
}]
}, {
"id": 2,
"name": "Secondary",
"cap": [{
"id": "1",
"name": "1s"
}, {
"id": "2",
"name": "T2s"
}]
}];
var ans = items.reduce(function(v, i) {
v[i.id] = i.cap;
return v;
}, {});
console.log(ans);
You can do this using a simple loop on the original array, and defining a new key: value pair into the object.
// Create the map
var map = {}
// For every 'item' within the 'items' array
items.forEach(item => {
// Map the item ID to the item.cap array
map[item.id] = item.cap
}
var items = [{
"id": 1,
"name": "Primary",
"cap": [{
"id": "1",
"name": "1s"
}, {
"id": "2",
"name": "T2s"
}]
}, {
"id": 2,
"name": "Secondary",
"cap": [{
"id": "1",
"name": "1s"
}, {
"id": "2",
"name": "T2s"
}]
}]
var map = {}
items.forEach(item => {
map[item.id] = item.cap
})
console.log(map)
Using ES6 Array.from() method.
var items = [{
"id": 1,
"name": "Primary",
"cap": [{
"id": "1",
"name": "1s"
}, {
"id": "2",
"name": "T2s"
}]
},{
"id": 2,
"name": "Secondary",
"cap": [{
"id": "1",
"name": "1s"
}, {
"id": "2",
"name": "T2s"
}
]
}];
var obj = {};
var res = Array.from(items, x => obj[x.id] = x.cap);
console.log(obj);

Javascript When null skip to the next record code modification

I have some code that's working great but I have a problem with.
Basically when it get to a record that's NULL it's adding a 0 to the array...
In this case the second record is NULL, so I'm getting:
[10, 0, 20]
What I need it to do is that if thsub is NULL then add nothing to the array and continue to the next record.
So the desired result in this case would be:
[10, 20]
Here's the full code:
var data = {
"cars": [{
"id": "1",
"name": "name 1",
"thsub": [{
"id": "11",
"name": "sub 1",
"stats": {
"items": 5,
},
"ions": null
}, {
"id": "22",
"name": "sub 2",
"stats": {
"items": 5,
},
"translations": null
}],
"image": null
},
{
"id": "2",
"name": "name 2",
"thsub": null, //this will break the code
"image": null
},
{
"id": "54",
"name": "name something",
"thsub": [{
"id": "65",
"name": "sub 1",
"stats": {
"items": 10,
},
"ions": null
}, {
"id": "22",
"name": "sub 2",
"stats": {
"items": 10,
},
"translations": null
}],
"image": null
}
]
}
var thCount = [];
for (var l = 0, m = data.cars.length; l < m; l++) {
thCount[l] = 0;
if (data.cars[l].thsub) {
for (var i = 0, j = data.cars[l].thsub.length; i < j; i++) {
if (data.cars[l].thsub[i].stats) {
thCount[l]+=data.cars[l].thsub[i].stats.items;
}
}
}
}
console.log(thCount);
How can I do this?
You could push only a value, if thsub is set.
var data = { cars: [{ id: "1", name: "name 1", thsub: [{ id: "11", name: "sub 1", stats: { items: 5, }, ions: null }, { id: "22", name: "sub 2", stats: { items: 5, }, translations: null }], image: null }, { id: "2", name: "name 2", thsub: null, image: null }, { id: "54", name: "name something", thsub: [{ id: "65", name: "sub 1", stats: { items: 10, }, ions: null }, { id: "22", name: "sub 2", stats: { items: 10, }, translations: null }], image: null }] },
thCount = [];
for (var l = 0, m = data.cars.length; l < m; l++) {
if (data.cars[l].thsub) {
thCount.push(0);
for (var i = 0, j = data.cars[l].thsub.length; i < j; i++) {
if (data.cars[l].thsub[i].stats) {
thCount[thCount.length - 1] += data.cars[l].thsub[i].stats.items;
}
}
}
}
console.log(thCount);
solution
you need to add variable and then push to array only if there is something.
var data = {
"cars": [{
"id": "1",
"name": "name 1",
"thsub": [{
"id": "11",
"name": "sub 1",
"stats": {
"items": 5,
},
"ions": null
}, {
"id": "22",
"name": "sub 2",
"stats": {
"items": 5,
},
"translations": null
}],
"image": null
},
{
"id": "2",
"name": "name 2",
"thsub": null, //this will break the code
"image": null
},
{
"id": "54",
"name": "name something",
"thsub": [{
"id": "65",
"name": "sub 1",
"stats": {
"items": 10,
},
"ions": null
}, {
"id": "22",
"name": "sub 2",
"stats": {
"items": 10,
},
"translations": null
}],
"image": null
}
]
}
var thCount = [];
for (var l = 0, m = data.cars.length; l < m; l++) {
if (data.cars[l].thsub) {
var tmp = 0;
for (var i = 0, j = data.cars[l].thsub.length; i < j; i++) {
if (data.cars[l].thsub[i].stats) {
tmp+=data.cars[l].thsub[i].stats.items;
}
thCount.push(tmp);
}
}
}
console.log(thCount);
You can create new variable inside for loop and use push() instead if its not 0.
var data = {"cars":[{"id":"1","name":"name 1","thsub":[{"id":"11","name":"sub 1","stats":{"items":5},"ions":null},{"id":"22","name":"sub 2","stats":{"items":5},"translations":null}],"image":null},{"id":"2","name":"name 2","thsub":null,"image":null},{"id":"54","name":"name something","thsub":[{"id":"65","name":"sub 1","stats":{"items":10},"ions":null},{"id":"22","name":"sub 2","stats":{"items":10},"translations":null}],"image":null}]}
var thCount = [];
for (var l = 0, m = data.cars.length; l < m; l++) {
var count = 0
if (data.cars[l].thsub) {
for (var i = 0, j = data.cars[l].thsub.length; i < j; i++) {
if (data.cars[l].thsub[i].stats) {
count += data.cars[l].thsub[i].stats.items;
}
}
}
if (count != 0) thCount.push(count)
}
console.log(thCount);
The line thCount[l] = 0; will cause to add an element to thCount regardless of your condition if (data.cars[l].thsub)
You can use another variable and increase it only when we want to add something to our array:
var data = {
"cars": [{
"id": "1",
"name": "name 1",
"thsub": [{
"id": "11",
"name": "sub 1",
"stats": {
"items": 5,
},
"ions": null
}, {
"id": "22",
"name": "sub 2",
"stats": {
"items": 5,
},
"translations": null
}],
"image": null
},
{
"id": "2",
"name": "name 2",
"thsub": null, //this will break the code
"image": null
},
{
"id": "54",
"name": "name something",
"thsub": [{
"id": "65",
"name": "sub 1",
"stats": {
"items": 10,
},
"ions": null
}, {
"id": "22",
"name": "sub 2",
"stats": {
"items": 10,
},
"translations": null
}],
"image": null
}
]
}
var thCount = [];
for (var l = 0, k = -1, m = data.cars.length; l < m; l++) {
if (data.cars[l].thsub) {
thCount[++k] = 0;
for (var i = 0, j = data.cars[l].thsub.length; i < j; i++) {
if (data.cars[l].thsub[i].stats) {
thCount[k] += data.cars[l].thsub[i].stats.items;
}
}
}
}
console.log(thCount); //alert(thCount);
There has been some answers about how to fix the loop, so the basic problem is with the thCount[l] = 0 line. You can also use higher order functions to loop through the object which results in a better readable code in my opinion:
var data = {
"cars": [{
"id": "1",
"name": "name 1",
"thsub": [{
"id": "11",
"name": "sub 1",
"stats": {
"items": 5,
},
"ions": null
}, {
"id": "22",
"name": "sub 2",
"stats": {
"items": 5,
},
"translations": null
}],
"image": null
},
{
"id": "2",
"name": "name 2",
"thsub": null, //this will break the code
"image": null
},
{
"id": "54",
"name": "name something",
"thsub": [{
"id": "65",
"name": "sub 1",
"stats": {
"items": 10,
},
"ions": null
}, {
"id": "22",
"name": "sub 2",
"stats": {
"items": 10,
},
"translations": null
}],
"image": null
}
]
}
var thCount = data.cars.filter(function(car){
return car.thsub;
}).map(function(car){
return car.thsub.reduce(function(a,b){
return a.stats.items + b.stats.items;
});
});
console.log(thCount)
First, you filter out all objects that have no thsub. Then you map those entries to new values. You get those values with the reduce-function, which sums up all the items-values in the stats.
One also might consider a nested reduce approach e.g. like the following ...
var data = {
"cars": [{
"id": "1",
"name": "name 1",
"thsub": [{
"id": "11",
"name": "sub 1",
"stats": {
"items": 5
},
"translations": null
}, {
"id": "22",
"name": "sub 2",
"stats": {
"items": 5
},
"translations": null
}],
"image": null
}, {
"id": "2",
"name": "name 2",
"thsub": null,
"image": null
}, {
"id": "54",
"name": "name something",
"thsub": [{
"id": "65",
"name": "sub 1",
"stats": {
"items": 10
},
"translations": null
}, {
"id": "22",
"name": "sub 2",
"stats": {
"items": 10
},
"translations": null
}],
"image": null
}]
};
var thCount = data.cars.reduce(function (collector, carItem) {
var
thSubs = carItem.thsub;
//if (Array.isArray(thSubs)) { ... }
if ((thSubs != null) && (thSubs.length >= 1) && Number.isFinite(thSubs.length)) {
collector.push(
thSubs.reduce(function (count, subItem) {
return (count + subItem.stats.items);
}, 0)
);
}
return collector;
}, []);
console.log(thCount);

Underscore Create array of objects from JSON object

I have following JSON structure:
{
"shops": {
"categories": {
"cat_1": {
"id": "1",
"label": "Men's Fashions",
"Brands": [{
"id": "2",
"name": "Smith"
}]
},
"cat_2": {
"id": "2",
"label": "Restaurants",
"Brands": [{
"id": "3",
"name": "KFC"
}, {
"id": "4",
"name": "SUBWAY"
}, {
"id": "5",
"name": "MLD"
}, {
"id": "6",
"name": "THAI"
}]
},
"cat_3": {
"id": "3",
"label": "Specialty Shops",
"Brands": [{
"id": "7",
"name": "BODY SHOP"
}]
}
}
}
}
I'd like to achieve something like this:
[{
"categoryid": "1",
"id": "2",
"label": "Men's Fashions",
"name": "Smith"
},
{
"categoryid": "2",
"id": "3",
"label": "Restaurants",
"name": "KFC"
},
{
"categoryid": "2",
"id": "4",
"label": "Restaurants",
"name": "SUBWAY"
},
{
"categoryid": "2",
"id": "5",
"label": "Restaurants",
"name": "MLD"
},
{
"categoryid": "2",
"id": "6",
"label": "Restaurants",
"name": "THAI"
}, {
"categoryid": "3",
"id": "7",
"label": "Specialty Shops",
"name": "BODY SHOP"
},
]
Is there an elegant way to achieve it using underscore?
I tried to use nested _.each() to do that, but feel there might be something better.
generateArray: function(obj) {
var newResult = [];
_.each(obj.categories, function(c) {
_.each(c.Brands, function(d) {
newResult.push({
"categoryid": c.id,
"id": d.id,
"label": c.label,
"name": d.name
});
});
});
return newResult;
}
Anyone can advise me which way is more efficiency at running time?
mine or #Artyom Neustroev or #Anthony Chu ?
You don't really need underscore for that task. Use simple for .. in .. and for (...) loops:
var json = {...};
var result = [];
for (var catKey in json.shops.categories) {
var currentCategory = json.shops.categories[catKey];
for (var i = 0; i < currentCategory.Brands.length; i++) {
var currentBrand = currentCategory.Brands[i];
result.push({
categoryid: currentCategory.id,
label: currentCategory.label,
id: currentBrand.id,
name: currentBrand.name
});
}
}
Fiddle here
Instead of each()'s, here's a way to do it with map()'s...
var output = _.chain(input.shops.categories)
.map(function (category) {
return _(category.Brands).map(function (brand) {
return { categoryId: category.id,
id: brand.id,
label: category.label,
name: brand.name
};
});
}).flatten().value();
JSFIDDLE

Categories

Resources