How to sum values of objects and push it in an array - javascript

I have an array of objects which is dynamic and depend on the selection of rows of a table. An example of it:
var obj = [
{ name: "test1", totalCosts: 45560, actualTotalCosts: 652112, riskCosts: 65442 },
{ name: "test2", totalCosts: 3434, actualTotalCosts: 25252, riskCosts: 34234 },
{ name: "test3", totalCosts: 23123, actualTotalCosts: 23242, riskCosts: 0 },
];
After this array is generated I want to call a function which pushes one more row in this array and names it "total" and sums all the respected values which would look like this:
{name: "total", totalCosts:72117, actualTotalCosts:700606 , risksCosts: 99676 }
obj[0].totalCosts + obj[1].totalCosts + obj[2].totalCosts = obj[3].totalCosts
I tried writing one with my limited knowledge, but that function instead of summing up the values from all three objects, summed up the entire object into one.
function sum1( obj ) {
var result1 = [];
for (var i = 0; i < obj.length; i++) {
var sum = 0, arr = [];
for (var key in obj[i]) {
if (key != 'name') {
sum += obj[i][key];
arr.push(sum[key]);
}
}
result1.push(arr);
return result1;
}
}
Please provide a function which can sum all the objects and return the array with the totals. I also tried using d3.sum but was not successful.

You can take a functional approach with the aid of d3.sum...
obj.push(d3.keys(obj[0]) //get the keys from obj[0]
.reduce(function(sumRow, sumCol) { //construct a summary row
var isNum = !isNaN(obj[0][sumCol]) //only sum numeric fields
return (sumRow[sumCol] = (isNum ? d3.sum(obj, function(row) {
return row[sumCol] //accessor for the column for d3.sum
}) : "All"), sumRow) //append the sum col to the sum row object
},{})); //initial value for reduce is {}
Working example
(function() {
var obj = [{
name: "test1",
name2: "type1",
totalCosts: 45560,
actualTotalCosts: 652112,
riskCosts: 65442
}, {
name: "test2",
name2: "type2",
totalCosts: 3434,
actualTotalCosts: 25252,
riskCosts: 34234
}, {
name: "test3",
name2: "type3",
totalCosts: 23123,
actualTotalCosts: 23242,
riskCosts: 0
}];
obj.push(d3.keys(obj[0])
.reduce(function(sumRow, sumCol) {
var isNum = !isNaN(obj[0][sumCol])
return (sumRow[sumCol] = (isNum ? d3.sum(obj, function(row) {
return row[sumCol]
}) : "All"), sumRow)
}, {}));
d3.select("#result").text(JSON.stringify(obj))
})()
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="result"></div>

Note: It's important to realize that what you are calling var obj is actually an array.
That being said, you can iterate over your array and do this:
function sumAll(arr) {
// Create variables for the costs we're tracking
var totalCosts = 0;
var actualTotalCosts = 0;
var riskCosts = 0;
arr.forEach(function(elem) {
// At each iteration of our loop, increase the appropriate variables by their appropriate values
if (elem.hasOwnProperty('totalCosts')) {
totalCosts += elem.totalCosts;
}
if (elem.hasOwnProperty('actualTotalCosts')) {
actualTotalCosts += elem.actualTotalCosts;
}
if (elem.hasOwnProperty('riskCosts')) {
riskCosts += elem.riskCosts
}
});
// Return an object with the information we'd like to have
return {
name: 'total',
totalCosts: totalCosts,
actualTotalCosts: actualTotalCosts,
riskCosts: riskCosts
}
}
From your code:
var obj = [
{ name: "test1", totalCosts: 45560, actualTotalCosts: 652112, riskCosts: 65442 },
{ name: "test2", totalCosts: 3434, actualTotalCosts: 25252, riskCosts: 34234 },
{ name: "test3", totalCosts: 23123, actualTotalCosts: 23242, riskCosts: 0 },
];
Calling my function:
sumAll(obj) // {name: "total", totalCosts: 72117, actualTotalCosts: 700606, riskCosts: 99676}

Related

Reactjs if conditions

How can I control the loop in reactjs? I just want that if the label or Group is equal it will not be displayed
generateAvailableOptions(data){
const availableGroups = [];
data.map(function(food){
availableGroups.push({
label: food.Group,
options: [
{ value: 'canAdd'+food.groupsid, label: food.description}
],
})
});
this.setState({availableGroups: availableGroups})
}
The actual result
Vegetables:
Carrots
Vegetables:
Cabbage
Vegetables:
Potato
Fruits:
Mango
Fruits:
Apple
Fruits:
Pineapple
This is what I want results:
Vegetables:
Carrots
Cabbage
Potato
Fruits:
Mango
Apple
Pineapple
Here's the code:
const data = [
{Group:'vegetable',description:'Carrots',groupsid:1},
{Group:'vegetable',description:'Cabbage',groupsid:1},
{Group:'vegetable',description:'Potato',groupsid:1},
{Group:'fruit',description:'Mango',groupsid:2},
{Group:'fruit',description:'Apple',groupsid:2}
]
generateAvailableOptions(data){
const result = data.reduce((item,curr)=> {
if(!item[curr.Group]) item[curr.Group] = [];
item[curr.Group].push({value: 'canAdd'+curr.groupsid, label: curr.description});
return item;
},{});
const availableGroups = [];
Object.entries(result).forEach(entry => {
const [key, value] = entry;
availableGroups.push({
"label":key,
"options": value
})
});
this.setState({availableGroups: availableGroups});
}
You can see the result : https://es6console.com/krhjx0rz/
If I understand correctly you need to group by your array based on keys.
You can use Object.keys to get key of all object and then check to see if exists or not. if exists push new value if not assign to current array value.
So try this one:
var data = [{ "Vegetables": "Carrots" }, { "Vegetables": "Cabbage" }, { "Vegetables": "Potato", }, { "Fruits": "Mango" }, { "Fruits": "Apple" },{ "Fruits": "Pineapple" }]
var obj = {};
for (let a in data) {
let keys = Object.keys(data[a]);
for (var i = 0; i < keys.length; i++) {
if (obj[keys[i]])
obj[keys[i]].push(data[a][keys[i]])
else
obj[keys[i]] = [data[a][keys[i]]];
}
}
console.log(obj);
var data = [
{ Group: "Veg", description: "potato", groupsid: 1 },
{ Group: "Veg", description: "cucumber", groupsid: 1 },
{ Group: "Fruit", description: "tomato", groupsid: 2 }
];
function generateAvailableOptions(data) {
const distinctFoodObjs = [];
// eslint-disable-next-line
data.map((item) => {
var findItem = distinctFoodObjs.find((x) => x.Group === item.Group);
if (!findItem) distinctFoodObjs.push({ label: item.Group, options: [] });
});
// eslint-disable-next-line
data.map((food) => {
// eslint-disable-next-line
distinctFoodObjs.map((arrElem) => {
if (arrElem.label === food.Group) {
arrElem.options.push({
value: "canAdd" + food.groupsid,
label: food.description
});
}
});
});
console.log(distinctFoodObjs);
}
generateAvailableOptions(data);

Convert arrays to nested objects javascript

I have a array of objects, like this:
var tryArray = [{
name: 'name1',
subname: 'subname1',
symbolname: 'symbol1'
},
{
name: 'name1',
subname: 'subname11',
symbolname: 'symbol11'
},
{
name: 'name2',
subname: 'subname2',
symbolname: 'symbol2'
},
{
name: 'name2',
subname: 'subname22',
symbolname: 'symbol22'
},
{
name: 'name3',
subname: 'subname3',
symbolname: 'symbol3'
},
{
name: 'name3',
subname: 'subname33',
symbolname: 'symbol33'
}];
I want to convert this array into a nested object, where the name will be parent of subname, and subname will be parent of symbolname. For example:
result = {
name1: {
subname1: [symbolname1],
subname11: [symbolname11]
},
name2: {
subname2: [symbolname2],
subname22: [symbolname22]
},
name3: {
subname3: [symbolname3],
subname33: [symbolname33]
}
}
I have tried using reduce like this
tryArray.reduce((object, item) => {
object[item.name] = {[item.subname]: [item.symbolname]}
},{})
but it returned only one subname. any ideas how to resolved this, thank you so much
reduce expects a return value like:
var tryArray = [{"name":"name1","subname":"subname1","symbolname":"symbol1"},{"name":"name1","subname":"subname11","symbolname":"symbol11"},{"name":"name2","subname":"subname2","symbolname":"symbol2"},{"name":"name2","subname":"subname22","symbolname":"symbol22"},{"name":"name3","subname":"subname3","symbolname":"symbol3"},{"name":"name3","subname":"subname33","symbolname":"symbol33"}]
var result = tryArray.reduce((object, item) => {
object[item.name] = object[item.name] || {}; //Need to init name if not exst
object[item.name][item.subname] = [item.symbolname];
return object;
}, {})
console.log( result );
If you have multiple symbolnames in a subname, you can:
var tryArray = [{"name":"name1","subname":"subname1","symbolname":"symbol1"},{"name":"name1","subname":"subname11","symbolname":"symbol11"},{"name":"name2","subname":"subname2","symbolname":"symbol2"},{"name":"name2","subname":"subname22","symbolname":"symbol22"},{"name":"name3","subname":"subname3","symbolname":"symbol3"},{"name":"name3","subname":"subname33","symbolname":"symbol33"}];
var result = tryArray.reduce((object, item) => {
object[item.name] = object[item.name] || {}; //Need to init name if not exist
object[item.name][item.subname] = object[item.name][item.subname] || []; //Need to subname name if not exist
object[item.name][item.subname].push(item.symbolname); //Push the symbolname
return object;
}, {});
console.log(result);

javascript - reorder array of objects depending on property

I am building a select dropdown input for a webpage. I want to make a 'popular' options group which appears at the top of the dropdown.
I am working with data in the following structure.
I need to find a way to reorder the items inside the people array based on their name.
For example moving:
pogo-stick from toys[2] -> toys[0]
cards from toys[3] to toys [2]
I will have an array of popular toys such as:
popularToys: [
"cards", "pogo-stick"
]
How can I iterate through the array of objects and move them in to the new order?
Data:
{
"toys": [
{
"name": "car",
"price": "10"
},
{
"name": "duck",
"price": "25"
},
{
"name": "pogo-stick",
"price": "60"
},
{
"name": "cards",
"price": "5"
}
]
}
Use forEach() loop where you can find the index of the toy object and swap:
var popularToys = [
"cards", "pogo-stick"
]
var data = {
"toys": [
{
"name": "car",
"price": "10"
},
{
"name": "duck",
"price": "25"
},
{
"name": "pogo-stick",
"price": "60"
},
{
"name": "cards",
"price": "5"
}
]
};
popularToys.forEach(function(toy, index){
var toyObjIndex = data.toys.findIndex(x => x.name==toy);
//swap
var tempObj = data.toys[toyObjIndex];
data.toys[toyObjIndex] = data.toys[index];
data.toys[index] = tempObj;
});
console.log(data);
Using a combination of map and filter we are able to split the required logic into to methods (Maybe more readable)
Popular() returns a filtered Array of any of the toy items that have a name property that corresponds with the current name in the iteration of popular
Rest() returns a filtered Array of toys where the name property of the toy in the iteration does not exist in the Array of String in popular
const toys = [
{
name: 'car',
price: '10'
},
{
name: 'exception',
price: '999999'
},
{
name: 'duck',
price: '25'
},
{
name: 'pogo-stick',
price: '60'
},
{
name: 'cards',
price: '5'
},
{
name: 'another !exception',
price: '100000'
},
{
name: 'pogo-stick',
price: 'A MILLION POUNDS'
},
{
name: 'duck',
price: '100'
}
]
const popular = [
'cards',
'pogo-stick',
'car',
'duck'
]
const Popular = () => {
return [].concat(...popular.map(n => toys.filter(({name}) => name === n)))
}
const Rest = () => toys.filter(({name}) => popular.indexOf(name) === -1)
let ordered = [].concat(...Popular(), ...Rest())
console.log(ordered)
You could use a custom sort function
var popularToys = [
"cards", "pogo-stick"
]
var data = {
"toys": [
{
"name": "car",
"price": "10"
},
{
"name": "duck",
"price": "25"
},
{
"name": "pogo-stick",
"price": "60"
},
{
"name": "cards",
"price": "5"
}
]
};
function popularFirst(a, b) {
var aIsPopular = popularToys.indexOf(a.name) > -1;
var bIsPopular = popularToys.indexOf(b.name) > -1;
if (aIsPopular) {
// b could be popular or not popular, a still comes first
return -1;
} else if (bIsPopular) {
// a isnt popular but b is, change the order
return 1;
} else {
// no change
return 0;
}
}
console.log(data.toys.sort(popularFirst));
function compare(a,b) {
if (a.name < b.name)
return -1;
if (a.name > b.name)
return 1;
return 0;
}
toys.sort(compare);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

Split array into chunk of different size on the basis of their attribute

I have this following array
var array=[{ semster:1, name:Book1 }, { semster:1, name:Book2 }, { semster:2, name:Book4 }, { semster:3, name:Book5 }, { semster:3, name:Book6 }, { semster:4, name:Book7 }]
Now I want to sort my array to split the current array into chunks of array like following
var array=[[{ semster:1, name:Book1 }, { semster:1, name:Book2 }],[ { semster:2, name:Book4 }], [{ semster:3, name:Book5 }, { semster:3, name:Book6 }], [{ semster:4, name:Book7 }]]
I have tried to achieve this with following code :
function splitIntoSubArray(arr, count) {
var newArray = [];
while (arr.length > 0) {
newArray.push(arr.splice(0, count));
}
return newArray;
}
But this can only divide the array on the basis of fixed size. Any kind of suggestion is appreciated.
Thanks
You can simply use Array.reduce() to group items by semester. Object.values() on the map gives you the desired result.
var array=[{ semster:1, name:"Book1" }, { semster:1, name:"Book2" }, { semster:2, name:"Book4" }, { semster:3, name:"Book5" }, { semster:3, name:"Book6" }, { semster:4, name:"Book7" }];
var result = Object.values(array.reduce((a, curr)=>{
(a[curr.semster] = a[curr.semster] || []).push(curr);
return a;
},{}));
console.log(result);
You could reduce the array by checking the last group with the same semester.
var array = [{ semester: 1, name: 'Book1' }, { semester: 1, name: 'Book2' }, { semester: 2, name: 'Book4' }, { semester: 3, name: 'Book5' }, { semester: 3, name: 'Book6' }, { semester: 4, name: 'Book7' }],
grouped = array.reduce((r, o) => {
var last = r[r.length - 1];
if (last && last[0].semester === o.semester) {
last.push(o);
} else {
r.push([o]);
}
return r;
}, []);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Build array from another array if some key are identical using JavaScript

I have an array of data. Some of the key in the array are same. I would like to create a new array based on the key and add the other data.
This is my array
var myObjOne = [
{
"name":"John",
"id":1,
"car":"maruti"
},
{
"name":"John",
"id":2,
"car":"wolks"
},
{
"name":"John",
"id":3,
"car":"bmw"
},
{
"name":"Peter",
"id":4,
"car":"alto"
},
{
"name":"Peter",
"id":5,
"car":"swift"
}
];
I would like to convert the array in to the below format.
var myObj = [
{
"name":"John",
"items": [
{ "id":1, "car":"maruti" },
{ "id":2, "car":"wolks" },
{ "id":3, "car":"bmw" }
]},
{
"name":"Peter",
"items": [
{ "id":4, "car":"alto" },
{ "id":5, "car":"swift" },
]
}
];
I am working on a node environment.
You can create an object using Array#reduce first which maps name with items, and then create the final array by looping over the intermediate map using a for...of loop:
var source = [{"name":"John","id":1,"car":"maruti"},{"name":"John","id":2,"car":"wolks"},{"name":"John","id":3,"car":"bmw"},{"name":"Peter","id":4,"cars":"alto"},{"name":"Peter","id":5,"cars":"swift"}];
const map = source.reduce((acc, {name, ...obj}) => {
if (!acc[name]) {
acc[name] = [];
}
acc[name].push(obj);
return acc;
}, {});
const result = [];
for (let[name, items] of Object.entries(map)) {
result.push({name, items});
}
console.log(result);
Array.reduce is at rescue.This method accepts an accumulator and current
item. Check in the accumulator if there exist an object where the value of name property is John or Peter
var myObjOne = [{
"name": "John",
"id": 1,
"car": "maruti"
},
{
"name": "John",
"id": 2,
"car": "wolks"
},
{
"name": "John",
"id": 3,
"car": "bmw"
},
{
"name": "Peter",
"id": 4,
"car": "alto"
},
{
"name": "Peter",
"id": 5,
"car": "swift"
}
];
var newObj = myObjOne.reduce(function(acc, curr, currIndex) {
// using findIndex to check if there exist an object
// where the value of the name property is John, Peter
// if it exist it will return the index else it will return -1
let ifNameExist = acc.findIndex(function(item) {
return item.name === curr.name;
})
// if -1 then create a object with name and item property and push
// it to the accumulator
if (ifNameExist === -1) {
let nameObj = {};
nameObj.name = curr.name;
nameObj.items = [];
nameObj.items.push({
id: curr.id,
car: curr.car
})
acc.push(nameObj)
} else {
// if such an object already exist then just update the item array
acc[ifNameExist].items.push({
id: curr.id,
car: curr.car
})
}
return acc;
}, []);
console.log(newObj)
Use .reduce to group by name, and use .find inside the reducer to find if the matching name has already been added:
const input=[{"name":"John","id":1,"car":"maruti"},{"name":"John","id":2,"car":"wolks"},{"name":"John","id":3,"car":"bmw"},{"name":"Peter","id":4,"cars":"alto"},{"name":"Peter","id":5,"cars":"swift"}]
const output = input.reduce((a, { name, ...item }) => {
const foundNameObj = a.find(nameObj => nameObj.name === name);
if (foundNameObj) foundNameObj.items.push(item);
else a.push({ name, items: [item] });
return a;
}, []);
console.log(output);

Categories