Multiply two values from api response and sum all the results - javascript

I'm getting info from an api, and what i wanna do is to multiply two different values from that response, and then sum the totals. I know how to sum all the values with reduce:
function getHistoricSales(){
$http.get('api/SomeApi')
.then(function(data){
$scope.salesResult = data.data.Response;
var hResults = $scope.salesResult.reduce((a, b) => a + b.Cost, 0);
$scope.historic = hResult.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
});
}
But, if per example, on that response not only get the Cost (b.Cost), but the Quantity too. So, how can i in first place multiply every Costby it's own Quantity and then sum the results?
I'm using Javascript and AngularJs.
Hope you can help me. Thanx in advance...

I think what you're looking for is:
var hResults = $scope.salesResult
.map(sr => sr.Cost * sr.Quantity)
.reduce((a, b) => a + b);
So you want to transform each sales result (with map) into its own result (i.e. cost * quantity) and then sum those (with reduce).
For example:
let data = [
{Cost: 10, Quantity: 15},
{Cost: 5, Quantity: 11},
{Cost: 2, Quantity: 110},
{Cost: 5, Quantity: 90},
]
let result = data
.map(sr => sr.Cost * sr.Quantity)
.reduce((a, b) => a + b);
console.log(result);

If each item in $scope.salesResult optionally has a quantity property, you'll need to make sure you're not multiplying by an undefined value. Thus, your reduce() should take this condition into account.
var salesResult = [
// Some items only have the cost
{ cost: 10 },
{ cost: 10 },
// Some items might also have a quantity
{ cost: 10, quantity: 10 },
{ cost: 10, quantity: 10 },
];
var hResults = salesResult.reduce((total, result) =>
total + (result.quantity
? result.cost * result.quantity
: result.cost), 0);
console.log(hResults); // 220

Related

Find the highest number in a json object with javascript and a corresponding index or another value

This javascript find the highest number but i want the corresponding id and index too, or the corresponding id. This is not a duplicate question since i'm looking for the id or the index and not just finding the highest number.
const shots = [{
id: 1,
amount: 2
},
{
id: 2,
amount: 4
},
{
id: 3,
amount: 52
},
{
id: 4,
amount: 36
},
{
id: 5,
amount: 13
},
{
id: 6,
amount: 33
}
];
var highest = shots.reduce((acc, shot) => acc = acc > shot.amount ? acc : shot.amount, 0);
OR
var highest = Math.max.apply(Math, shots.map(function(o) { return o.amount; }))
In this example the highest number is 52 then it mean that the corresponding index is 2.
how to get this index value?
Finally, i need to get the corresponding id.
In real life, i should find the highest bitrate to get the corresponding highest quality video url.
Once you have the highest amount, you can .findIndex to get the object with that amount.
const shots=[{id:1,amount:2},{id:2,amount:4},{id:3,amount:52},{id:4,amount:36},{id:5,amount:13},{id:6,amount:33}];
const highest = Math.max(...shots.map(o => o.amount));
const index = shots.findIndex(o => o.amount === highest);
console.log(index, shots[index].id);
Or if you wanted to do it with just a single iteration
const shots=[{id:1,amount:2},{id:2,amount:4},{id:3,amount:52},{id:4,amount:36},{id:5,amount:13},{id:6,amount:33}];
let index = 0;
let best = -Infinity;
shots.forEach((shot, i) => {
if (shot.amount > best) {
best = shot.amount;
index = i;
}
});
console.log(index, shots[index].id);
If you only want the index to get to the ID, it's a bit easier.
const shots=[{id:1,amount:2},{id:2,amount:4},{id:3,amount:52},{id:4,amount:36},{id:5,amount:13},{id:6,amount:33}];
const best = shots.reduce((a, b) => a.amount > b.amount ? a : b);
console.log(best);

What's the simplest way to return the key with the largest value in an array of objects?

I'm making a simple RPG and trying to calculate which attribute should be increased when a character levels up. They have a potential limit for each attribute and I want to increment the attribute that is furthest from its potential.
I can loop through each attribute and subtract its current value from its potential value to get the difference. I can then push the difference to an array. The result looks like:
[
{Strength: 5},
{Dexterity: 6},
{Constitution: 3},
{Wisdom: 4},
{Charisma: 8}
]
Charisma is the key with the highest difference, so how can I evaluate this and return the name of the key (not the value itself)?
EDIT: Here is the logic which is used to get the array:
let difference = [];
let key;
for (key in currentAttributes) {
difference.push({[key]: potentialAttributes[key] - currentAttributes[key]});
};
Simple reduce with Object.entries
const items = [
{ Strength: 5 },
{ Dexterity: 6 },
{ Constitution: 3 },
{ Wisdom: 4 },
{ Charisma: 8 }
]
const biggest = items.reduce((biggest, current, ind) => {
const parts = Object.entries(current)[0] //RETURNS [KEY, VALUE]
return (!ind || parts[1] > biggest[1]) ? parts : biggest // IF FIRST OR BIGGER
}, null)
console.log(biggest[0]) // 0 = KEY, 1 = BIGGEST VALUE
Your data model is a bit weird with the array with objects, a better model would just be an object.
const items = {
Strength: 5,
Dexterity: 6,
Constitution: 3,
Wisdom: 4,
Charisma: 8
}
const biggest = Object.entries(items)
.reduce((biggest, current, ind) => {
const parts = current
return (!ind || parts[1] > biggest[1]) ? parts : biggest
}, null)
console.log(biggest[0])
You could create an object, take the entries and reduce the entries by taking the entry with the greatest value. At the end take the key from the entry.
var data = [{ Strength: 5 }, { Dexterity: 6 }, { Constitution: 3 }, { Wisdom: 4 }, { Charisma: 8 }],
greatest = Object
.entries(Object.assign({}, ...data))
.reduce((a, b) => a[1] > b[1] ? a : b)
[0];
console.log(greatest);
Sort in descending order and grab the first item:
let attributes = [
{Strength: 5},
{Dexterity: 6},
{Constitution: 3},
{Wisdom: 4},
{Charisma: 8}
];
//for convenience
const getValue = obj => Object.values(obj)[0];
//sort descending
attributes.sort((a, b) => getValue(b) - getValue(a));
let highest = attributes[0];
console.log(Object.keys(highest)[0]);
Alternatively, go though the array and find the highest score:
let attributes = [
{Strength: 5},
{Dexterity: 6},
{Constitution: 3},
{Wisdom: 4},
{Charisma: 8}
];
//for convenience
const getValue = obj => Object.values(obj)[0];
//find the highest score
let highest = attributes.reduce((currentHighest, nextItem) => getValue(currentHighest) > getValue(nextItem) ? currentHighest : nextItem);
console.log(Object.keys(highest)[0]);

Better way to convert JSON to arrays for graphing timeseries in C3?

I'm working on converting some JSON data into a format that will work for graphing a timeseries in C3, which takes an array of arrays as column input. I have my unique x values array, but I can't figure out a great way to get my y values. Once I get this done, I need to add y2 with numSold, but I think if I can solve this, I'll be able to figure that part out.
This is the final format I need for the data:
[
["x", "9-2-17", "9-4-17", "10-2-17"],
['item1-cost', 100, 150, 10],
['item3-cost', 200, null, 20],
...
]
There isn't a set number of dates or set number of items. It's whatever I read from the database. The item numbers aren't necessarily consecutive. We only care about graphing the data for items we have data for. But there won't be data for every date-item combination. When that happens, I need to insert a null to indicate that the item didn't have data for that date. Item numbers are 1-indexed.
I'm fine with using anything from lo-dash or D3 in addition to the plain JavaScript functions to solve this, but I'm trying to avoid hard to read code and inefficient code. I feel like others must have had a need for this and that there must be some sort of function like maybe a filter function that I should be using instead.
My current implementation is not as efficient as I'd like and is a bit hard to read. I'm using the item number as an index and making a sparse array that I'll have to condense later. Here's the psudocode:
For every d object in data
For the i index of d.date in uniqueDates
If values[d.item] is undefined
Fill values[d.item]] with null for uniqueDates.length
Set values[d.item][i] to d.cost
Convert values to dense format for graphing
Here's a link to the Fiddle I'm playing with:
https://jsfiddle.net/dbkidd/q3r3moqu/
var data = [
{date: '9-2-17', item: 1, cost: 100},
{date: '9-2-17', item: 3, cost: 200},
{date: '9-4-17', item: 1, cost: 150},
/* '9-4-17' does not have an entry for item 3 so cost should be counted as null */
{date: '10-2-17', item: 1, cost: 10},
{date: '10-2-17', item: 3, cost: 20}
]
var uniqueDates = _.uniq(_.flatMap(data, 'date'));
uniqueDates.unshift('x');
var values = [];
values.push(uniqueDates);
function getLabel(index) {
return 'item' + index + '-' + 'cost';
}
for (var d = 0; d < data.length; d++) {
var i = _.indexOf(uniqueDates, data[d].date);
if (data[d].item !== undefined) {
var item = data[d].item;
if (values[item] === undefined) {
values[item] = _.fill(Array(uniqueDates.length), null);
values[item][0] = getLabel(item);
}
values[item][i] = data[d].cost;
}
}
function checkIfUndefined(x) {
return (x !== undefined);
}
function sparseToDense(data) {
return data.filter(checkIfUndefined);
}
values = sparseToDense(values);
I was intrigued by this problem and came up with a first version. It's a little different than yours but here it is. I will note that I didn't try to sort the dates or rename the items to something useful but those can be added.
var data = [
{date: '9-2-17', item: 1, cost: 100},
{date: '9-2-17', item: 3, cost: 200},
{date: '9-4-17', item: 1, cost: 150},
/* '9-4-17' does not have an entry for item 3 so cost should be counted as null */
{date: '10-2-17', item: 1, cost: 10},
{date: '10-2-17', item: 3, cost: 20},
{date: '10-3-17', item: 2, cost: 2000}
]
// utility functions
const product = (...sets) =>
sets.reduce((acc, set) =>
_.flatten(acc.map(x => set.map(y => [ ...x, y ]))),
[[]]);
// the meat and potatoes
const builder = lookup => pairs => pairs.reduce((agg, [item, date]) => {
const out = _.cloneDeep(agg);
const value = _.get(lookup, [date, item, 'cost'], null);
const evalue = _.get(out, date, []);
evalue.push(value);
_.set(out, date, evalue);
return out;
}, {})
// setup data structures for searching
const byDateByItem = _.mapValues(_.groupBy(data, 'date'), x => _.keyBy(x, 'item'));
const items = _.uniq(data.map(x=>x.item));
const dates = _.uniq(data.map(x=>x.date));
// create all posibilities
const pairs = product(items, dates);
// populate possibilities with values
const hash = builder(byDateByItem)(pairs);
// put keys with values in their respective lists
const p = _.toPairs(hash).map(_.flatten);
// smash data into a matrix type thing
const table = [['x',...items], ...p];
// flip the table on it's side (╯°□°)╯︵ ┻━┻
const out = _.zip(...table);
console.log('out', out);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Node.js counting of my array object items

I have a application where I need count my doors. For example:
door1 has 60 people
door2 has 70 people
But how can I get the sum of each door because. I want push the sum of each door to my db, this data I get from my client every minute then I push the results to my db, and I clear the array for a next set of objects.
var a = [
{door: 1 , people: 20},
{door: 2 , people: 20},
{door: 1 , people: 10},
{door: 1 , people: 20},
{door: 2 , people: 50},
]
This a great example of when you can use map() and reduce() together:
Array.prototype.map() will run a function on each item in an array and transform each item into something else (returning a new array of the same length).
Array.prototype.reduce() will cumulatively calculate a single value based on each value in an array (returning just a single value).
var total = a.map(function(e) {
return e.people
})
.reduce(function(a, b) {
return {a + b};
})
In the example above we first use map() to transform each object in the array into just its 'people' value. So after this step we have an array that looks like:
[20, 20, 10, 20, 50]
Then we call reduce() on that array, which cumulatively adds the numbers together.
In ES6, this can be written even more succintly as:
let total = a.map(o => o.people).reduce((a,b) => a + b);
var a = [
{door: 1 , people: 20},
{door: 2 , people: 20},
{door: 1 , people: 10},
{door: 1 , people: 20},
{door: 2 , people: 50},
];
var sum = {};
for(var i=0;i<a.length;i++){
sum[a[i].door] = sum[a[i].door] || 0;
sum[a[i].door] += a[i].people;
}
console.log(sum);
var result = {}
a.map(i => result[i.door] = (result[i.door] || 0) + i.people)
and now just console.log(result)
Or you can even enhance the code using some syntactic sugar like that:
var result = {}
a.map({door, people} => result[i.door] = (result[door] || 0) + people)
values=[1,2].map(door=>a.filter(d=>d.door==door).reduce((val,d)=>val+d.people,0));
values will be [60,70],
For every door (1 and 2), get all elems of a where the elems door is door, then join these elems people value and map it back to the array. So every door is replaced with its referring value.
If you dont know the doors, you could create an associative object:
values=a.reduce((all,elem)=>{ return all[elem[door]]=all[elem.door]||0,all[elem.door]+=elem.people;},{});
this will result in:
{
1:60,
2:70
}
var array = [
{door: 1 , people: 20},
{door: 2 , people: 20},
{door: 1 , people: 10},
{door: 1 , people: 20},
{door: 2 , people: 50},
]
var res = [];
array.forEach(function(element) {
var e = res.find(function(data) {
return data.door == element.door;
});
if(e) {
element.people = e.people + element.people;
} else {
res.push({
door: element.door,
people: element.people
});
}
});
I don't know your desired result format, but if an object is good and taking into account you don't know about your doors beforehand, using just reduce() could be enough.
var a = [
{door: 1 , people: 20},
{door: 2 , people: 20},
{door: 1 , people: 10},
{door: 1 , people: 20},
{door: 2 , people: 50},
]
var result = a.reduce((accumulator, currentValue) => {
if (!accumulator[currentValue.door]) {
// set property the first time you find a door
accumulator[currentValue.door] = 0;
}
// sum the number of people each door in each iteration
accumulator[currentValue.door] += currentValue.people;
return accumulator;
}, {});
console.log(result)
The code above is easier to understand, but is a bit verbose. The callback of reduce() can be abbreviated like this:
a.reduce((accumulator, currentValue) => {
accumulator[currentValue.door] = accumulator[currentValue.door] || 0;
accumulator[currentValue.door] += currentValue.people;
return accumulator;
}, {});

Putting values as keys from reduced object with underscore

I managed to reduce and combine my Price Amount Object with this:
stooges = [{Price: 1.2, Amount: 40}, {Price: 1.3, Amount: 50}, {Price: 1.2, Amount: 60}];
inputarray = _.map _.groupBy(stooges, 'Price'), (v, k) ->
{ Price: k
Amount : _.reduce(v, ((m, i) -> m + i['Amount']), 0)}
console.log(inputarray)
Creates the following
[Object { Price="1.2", Amount=100}, Object { Price="1.3", Amount=50}]
But maybe the grouping is to much. anyhow i try to end up like this
[ { 1.2 : 100 } , { 1.3 : 50 } ]
With the Price as Key and the Amount as Value.
Damn i suck at this.
Try this:
_.map(_.groupBy(stooges, 'Price'), function(v, k){
var obj = {};
obj[k] = _.reduce(v, function(m, i){ return m + i['Amount'] }, 0);
return obj;
})
It returns the following:
[{ "1.2": 100 }, { "1.3": 50 }]
Edit: I'm not sure it's all that helpful to return an array. If you're using Lo-Dash instead of Underscore (which I recommend you do), you can use this instead which will return a single object with all the prices as keys to the total amount:
_(stooges).groupBy('Price').mapValues(function(stooge){
return _(stooge).pluck('Amount').reduce(function(total, amount){
return total + amount;
})
}).value()
It returns the following:
{ "1.2": 100, "1.3": 50 }
result1 = _.pluck inputarray,'Price'
result2 = _.pluck inputarray,'Amount'
boo = _.object(result1,result2);
Thanks got it now its not that elegant as yours!

Categories

Resources