Get value of an array given a certain condition in reactjs - javascript

I have the array
array = [
{ period: 1, currency: 1, cost: 100, count: 10 },
{ period: 1, currency: 2, cost: 200, count: 10 },
{ period: 2, currency: 1, cost: 300, count: 20 },
{ period: 3, currency: 3, cost: 400, count: 30 }
]
and I need you to sum the cost for the case that has the same period and different currency, but that does not sum the count and that the result is either of the two since they will be the same for the same period.
For example:
period = 1, sum(cost) = 300 y count = 10
period = 2, sum(cost) = 300 y count = 20
period = 3, sum(cost) = 400 y count = 30
How can I do this? Thanks

Here's a way to accomplish the task without using loops inside other loops. result ends up being an object that has a key for each period.
const array = [
{ period: 1, currency: 1, cost: 100, count: 10 },
{ period: 1, currency: 2, cost: 200, count: 10 },
{ period: 2, currency: 1, cost: 300, count: 20 },
{ period: 3, currency: 3, cost: 400, count: 330 }
];
const result = array.reduce((all, el) => {
if (all[el.period]) {
all[el.period].cost += el.cost;
} else {
all[el.period] = { ...el };
}
return all;
}, {});
console.log(result[1]);
console.log(result[2]);
console.log(result[3]);

You can solve this solution using given functional Array methods.
let array = [
{ period: 1, currency: 1, cost: 100, count: 10 },
{ period: 1, currency: 2, cost: 200, count: 10 },
{ period: 2, currency: 1, cost: 300, count: 20 },
{ period: 3, currency: 3, cost: 400, count: 330 },
];
const newArray = array.reduce((acc, elem) => {
if (acc.some((accElem) => accElem.period === elem.period)) {
return acc;
}
elem.sumCost = array
.filter((e) => e.period === elem.period)
.reduce((acc, e) => acc + e.cost, 0);
return acc.concat(elem);
}, []);
console.log(newArray);
the count, currency and cost variable equals fields of first element in matching variables.

Related

How to summarize total number in an array object

const dataAll = [ {id: 1, slp: { total: '3' }},{id: 2, slp: { total: '6' }},{id: 3, slp: { total: '5' }} ]
const res = dataAll.map((singleData) => singleData.data.slp.total);
const theres = JSON.stringify(res);
console.log(theres);
How can I add up all the total numbers from the array above?
so I can get the total of 3 + 6 + 5 = 14
and to get a number of the total number of an array in .length total of 3 example
You can easily add them using reduce and take the length as dataAll.length
const dataAll = [
{ id: 1, slp: { total: "3" } },
{ id: 2, slp: { total: "6" } },
{ id: 3, slp: { total: "5" } },
];
const total = dataAll.reduce((acc, curr) => +curr.slp.total + acc, 0);
const length = dataAll.length;
console.log(total, length);
try this:
const dataAll = [{ id: 1, slp: { total: '3' } }, { id: 2, slp: { total: '6' } }, { id: 3, slp: { total: '5' } }]
let total = 0
dataAll.map((singleData)=>{
total += parseInt(singleData.slp.total)
})
//Use whatever hook you need here to store the total value
setTotalHook(total, dataAll.length)
console.log(total)
You can use reduce to sum up values in an array.
const dataAll = [ {id: 1, slp: { total: '3' }},{id: 2, slp: { total: '6' }},{id: 3, slp: { total: '5' }} ]
const res = dataAll.reduce((partial_sum, a) => partial_sum + parseInt(a.slp.total), 0);
const theres = JSON.stringify(res);
console.log(theres);
For length just check the length property of the array.
To sum up the totals you can use reduce to iterate over the array of objects and add the value of total to the accumulator (initially set to zero) on each iteration. Note: you need to coerce that value to a number.
const data = [ {id: 1, slp: { total: '3' }},{id: 2, slp: { total: '6' }},{id: 3, slp: { total: '5' }} ];
const sum = data.reduce((acc, c) => {
// Coerce the string value to a number
// and add it to the accumulator
return acc + Number(c.slp.total);
}, 0);
console.log(`Length: ${data.length}`);
console.log(`Sum: ${sum}`);
You should be able to use reduce.
const dataAll = [ {id: 1, slp: { total: '3' }},{id: 2, slp: { total: '6' }},{id: 3, slp: { total: '5' }} ]
const sum = dataAll.reduce(((total, b) => total + parseInt(b.slp.total, 10)), 0);
const totalElements = dataAll.length;
console.log(sum, totalElements)

Forming an array by grouping using the properties from source array of objects in a particular order

I have an array of objects with the following structure that is being sent as response:
let sampleData = [
{ values: { High: 4, Low: 5, Medium: 7 } , time: "1571372233234" , sum: 16 },
{ values: { High: 5, Low: 3, Medium : 1 }, time: "1571372233234" , sum: 9},
{ time: "14354545454", sum: 0},
{ time: "14354545454", sum: 0} }
];
I need to take each key within each object inside array and form an array out of it. Basically grouping based on the key present in all the objects.If the object has no "values" it should return 0 across the val1,val2,val3.
But the issue , the order of the keys "high,low,medium" inside "values" object in the question is unpredictable. With whatever code I have written keys that are present in the first object will be grouped and follows that order. But I want be it any input order, It should always give me this order "High Medium Low" Order.
The resultant array of objects should look like and should always follow "High Medium Order":
result = [
{ name: 'High', data: [4, 5, 0, 0] },
{ name: 'Medium', data: [5, 3, 0, 0] },
{ name: 'Low', data: [7, 1, 0, 0] }
]
I have tried the following:
let sampleData = [{ values: { High: 4, Low: 5, Medium: 7 } , time: "1571372233234" , sum: 16 },{ values: { High: 5, Low: 3, Medium : 1 }, time: "1571372233234" , sum: 9},{ time: "14354545454", sum: 0},{ time: "14354545454", sum: 0 }];
const keySet = new Set(sampleData.flatMap(a => Object.keys(a.values || {})));
const merged = sampleData.reduce((acc, {
values = {}
}) => {
keySet.forEach(name => {
acc[name] = acc[name] || {
name,
data: []
};
acc[name].data.push(values[name] || 0);
});
return acc;
}, {});
console.log(merged);
You could take the result set and iterate for the key and array for the value.
let sampleData = [{ values: { High: 4, Low: 5, Medium: 7 }, time: "1571372233234", sum: 16 }, { values: { High: 5, Low: 3, Medium : 1 }, time: "1571372233234", sum: 9 }, { time: "14354545454", sum: 0 }, { time: "14354545454", sum: 0 }],
keys = ['High', 'Low', 'Medium'],
grouped = sampleData.reduce((r, { values = {} } = {}) => {
r.forEach(({ name, data }) => data.push(values[name] || 0));
return r;
}, keys.map(name => ({ name, data: [] })));
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can check for the undefined value when the attr values is not present.
sampleData.reduce((a, {values: {High = 0, Low = 0, Medium = 0} = {}})
^
|
+-- When attr "values" is
undefined initialize
as an "empty" object.
let sampleData = [{ values: { High: 4, Low: 5, Medium: 7 } , time: "1571372233234" , sum: 16 },{ values: { High: 5, Low: 3, Medium : 1 }, time: "1571372233234" , sum: 9},{ time: "14354545454", sum: 0},{ time: "14354545454", sum: 0}];
let result = Object.values(sampleData.reduce((a, {values: {High = 0, Low = 0, Medium = 0} = {}}) => {
(a["High"] || (a["High"] = {name: "High", data: []})).data.push(High);
(a["Low"] || (a["Low"] = {name: "Low", data: []})).data.push(Low);
(a["Medium"] || (a["Medium"] = {name: "Medium", data: []})).data.push(Medium);
return a;
}, Object.create(null)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You are returning an object and as such the order of the keys is not guaranteed. You probably want an array instead of an object.
You could just construct a final merged object like this
mergedFinal = [ merged['High'], merged['Medium'], merged['Low'] ]

How to sort an array of objects with amount and running balance keys

I am trying to reorder a nested array that has date, amount and balance columns. The balance column is pre-populated and is the source of truth for the order within items of the same day.
Sorting by day descending is the first step, however I am trying to return the order of transactions within a day to be correct according to the balance.
Given row "a" below, a.Amount + b.Balance should equal a.Balance. In the real dataset a single day would have less than 50 transactions and the same balance showing up twice within a day is very rare and maybe not something to account for.
Out of order:
[
{ date: 190105, amount: -40, balance: -10},
{ date: 190105, amount: 50, balance: 40},
{ date: 190104, amount: -20, balance: 0},
{ date: 190104, amount: 30, balance: 30},
{ date: 190103, amount: -10, balance: 20}
]
Correct order:
[
{ date: 190105, amount: 50, balance: 40 },
{ date: 190105, amount: -40, balance: -10 },
{ date: 190104, amount: 30, balance: 30 },
{ date: 190104, amount: -20, balance: 0 },
{ date: 190103, amount: -10, balance: 20 }
]
The first thing I tried was array.sort like below but this doesn't work as items don't necessarily need to be moved up or down depending on the check below, only moved to the index (so above) of the item that matches:
array.sort(function(a, b) {
return a.amount + b.balance - a.balance;
});
Figured it out.
The key is that the unique item in the sorted array is the last one, since this won't match the check we use to find next items (since there are none below it).
So if you isolate the last item then you can loop through the rest and build up the sorted array on top of it.
I think my examples above were a bit confusing with the dates and multiple same rounded numbers, the data in the working snippet below is more realistic.
var data = [
{ order: 10, amount: -3, balance: -257 },
{ order: 4, amount: -28, balance: 1280 },
{ order: 17, amount: -344, balance: 208 },
{ order: 13, amount: -27, balance: 74 },
{ order: 1, amount: -14, balance: 1986 },
{ order: 16, amount: 5, balance: 213 },
{ order: 8, amount: -129, balance: 1659 },
{ order: 14, amount: -113, balance: 101 },
{ order: 2, amount: 800, balance: 2000 },
{ order: 9, amount: 2045, balance: 1788 },
{ order: 11, amount: -216, balance: -254 },
{ order: 6, amount: -49, balance: 1310 },
{ order: 15, amount: 1, balance: 214 },
{ order: 5, amount: -2, balance: 1308 },
{ order: 12, amount: -112, balance: -38 },
{ order: 3, amount: -80, balance: 1200 },
{ order: 7, amount: -300, balance: 1359 }
];
var sorted = [];
// the last item is the one that
// doesn't have a balance match with any other item
// and is our starting point to figuring out the order
function findLastItem(a) {
var alength = a.length;
for (var i = 0; i < alength; i++) {
var matched = false;
for (var j = 0; j < alength; j++) {
var checkBalance = a[i].amount + a[j].balance - a[i].balance;
if (checkBalance == 0) {
matched = true;
break;
}
}
if (matched === false) {
sorted.push(a[i]);
a.splice(i, 1);
break;
}
}
}
// now loop through matching transactions
// start matching against the last item we found above
// and build the sorted array bottom up
function sortItems(a) {
for (var i = a.length - 1; i >= 0; i--) {
var matched = false;
for (var j = 0; j < a.length; j++) {
var checkBalance = a[j].amount + sorted[0].balance - a[j].balance;
if (checkBalance == 0) {
sorted.unshift(a[j]);
a.splice(j, 1);
break;
}
}
}
}
findLastItem(data);
sortItems(data);
console.log(sorted);

JavaScript objects array filter by minimum value of an attribute

I need to filter this object array by minimum value of 'rest' attribute. This is an one way to do it. Is there any other ways ?
'data' variable is a result of chained function. Is there any other way to do this without calling 'data' variable again inside Math.min() function.
let data =
[ { size: 5, qty: 2, rest: 0 },
{ size: 2, qty: 5, rest: 0 },
{ size: 1, qty: 10, rest: 0 },
{ size: 3, qty: 3, rest: 1 },
{ size: 4, qty: 2, rest: 2 } ]
let result = data.filter(e=> e.rest === Math.min(...data.map(f=>f.rest) ) );
console.log(result);
// result is
//[ { size: 5, qty: 2, rest: 0 },
// { size: 2, qty: 5, rest: 0 },
// { size: 1, qty: 10, rest: 0 }]
The easiest way is to pull the min function out of the filter like this:
let min = Math.min(...data.map(item => item.rest))
This is much more efficient as we are no longer loop over the data to find the min for every iteration of the filter.
We now have n * 2 passes instead of n^2 passes. (n is the size of your data set, 5 in this case)
Full example below:
let data = [
{ size: 5, qty: 2, rest: 0 },
{ size: 2, qty: 5, rest: 0 },
{ size: 1, qty: 10, rest: 0 },
{ size: 3, qty: 3, rest: 1 },
{ size: 4, qty: 2, rest: 2 }
]
let min = Math.min(...data.map(item => item.rest))
let result = data.filter(item => item.rest === min)
console.log(result)
Hope this helps!
Lloyd
data.map inside of data.filter is O(N^2); for an O(N) solution, iterate through data ahead of time to calculate the minimum, then filter by that minimum:
let data =
[ { size: 5, qty: 2, rest: 0 },
{ size: 2, qty: 5, rest: 0 },
{ size: 1, qty: 10, rest: 0 },
{ size: 3, qty: 3, rest: 1 },
{ size: 4, qty: 2, rest: 2 } ];
const minRest = Math.min(...data.map(({ rest }) => rest));
let result = data.filter(({ rest }) => rest === minRest);
console.log(result);
imo. the simplest/best solution is the one #CertainPerformance gave you.
Just wanted to add another solution with linear runtime (that truly iterates only once over the Array)
let data = [
{ size: 5, qty: 2, rest: 0 },
{ size: 2, qty: 5, rest: 0 },
{ size: 1, qty: 10, rest: 0 },
{ size: 3, qty: 3, rest: 1 },
{ size: 4, qty: 2, rest: 2 }
];
let result = data.reduce((result, item) => {
let minRest = result.length? result[0].rest: item.rest;
if (item.rest < minRest) {
minRest = item.rest;
result.length = 0;
}
if (item.rest === minRest) {
result.push(item);
}
return result;
}, []);
console.log(result);
#mathieux51 got me another idea how you can do this inside a method chain, but the readability/clarity/intention is not as good as with the other approaches:
let data = [
{ size: 5, qty: 2, rest: 0 },
{ size: 2, qty: 5, rest: 0 },
{ size: 1, qty: 10, rest: 0 },
{ size: 3, qty: 3, rest: 1 },
{ size: 4, qty: 2, rest: 2 }
];
let result = data.sort((a, b) => a.rest - b.rest)
.filter((item, index, array) => item.rest === array[0].rest);
console.log(result);
It sounds like you want to sort the list. I would do it as following:
const result = data.sort((a, b) => a.rest - b.rest)
Get Min or Max
Since no one mentioned this method I will update it here.
myArray.sort(function (a, b) {
return a.rest - b.rest
})
var min = myArray[0],
max = myArray[myArray.length - 1]
It has good readability/clarity/intentions.

Javascript get value from object based on key compared to its size smaller then next key

Trying to calculate shipping prices based on the weight of a package.
I have an Object containing prices for a given weight like
shippingPrices = {
'economy': {
[weight]: price,
. . .
}
};
Then I want to get the right shipping price with a function passing the weight of a package like:
addShippingPrice(700); // 700 is weight in grams
I've tried like so:
shippingPrices = {
'economy': {
2000: 7,
5000: 9,
10000: 10,
20000: 15,
30000: 22
}
};
var addShippingPrice = function(weight) {
var price = 0;
for( var maxWeight in shippingPrices.economy) {
maxWeight = parseInt(maxWeight, 10);
console.log(shippingPrices.economy[maxWeight]);
if(weight < maxWeight) {
// return price = shippingPrices.economy[maxWeight];
}
}
console.log('amount', price);
};
addShippingPrice(700);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
The "right" shipping price in this case would be 7 and if I call the function with weight 8000 addShippingPrice(8000); it should return 10
How can I achieve that? Also if it would be better to change the shippingPrices Object to Array I'll change it!
You could use an iterable structure, like
var shippingPrices = {
economy: [
{ weight: 2000, price: 7 },
{ weight: 5000, price: 9 },
{ weight: 10000, price: 10 },
{ weight: 20000, price: 15 },
{ weight: 30000, price: 22 }
],
priority: [
{ weight: 2000, price: 9 },
{ weight: 5000, price: 11 },
{ weight: 10000, price: 12 },
{ weight: 20000, price: 18 },
{ weight: 30000, price: 25 }
]
};
function getShippingPrice(type, weight) {
var price;
shippingPrices[type].some(function (a) {
if (a.weight >= weight) {
price = a.price;
return true;
}
});
return price;
}
var shippingPrices = { economy: [{ weight: 2000, price: 7 }, { weight: 5000, price: 9 }, { weight: 10000, price: 10 }, { weight: 20000, price: 15 }, { weight: 30000, price: 22 }], priority: [{ weight: 2000, price: 9 }, { weight: 5000, price: 11 }, { weight: 10000, price: 12 }, { weight: 20000, price: 18 }, { weight: 30000, price: 25 }] };
console.log(getShippingPrice('economy', 700));
console.log(getShippingPrice('economy', 8000));
ES6
function getShippingPrice(type, weight) {
return (shippingPrices[type].find(a => a.weight >= weight) || {}).price;
}
var shippingPrices = { economy: [{ weight: 2000, price: 7 }, { weight: 5000, price: 9 }, { weight: 10000, price: 10 }, { weight: 20000, price: 15 }, { weight: 30000, price: 22 }], priority: [{ weight: 2000, price: 9 }, { weight: 5000, price: 11 }, { weight: 10000, price: 12 }, { weight: 20000, price: 18 }, { weight: 30000, price: 25 }] };
console.log(getShippingPrice('economy', 700));
console.log(getShippingPrice('economy', 8000));
shippingPrices = {
'economy': {
2000: 7,
5000: 9,
10000: 10,
20000: 15,
30000: 22
},
'priority': {
2000: 9,
5000: 11,
10000: 12,
20000: 18,
30000: 25
}
};
var addShippingPrice = function(weight) {
var price = 0;
for (var maxWeight in shippingPrices.economy) {
maxWeight = parseInt(maxWeight);
if (weight <= maxWeight) {
price = shippingPrices.economy[maxWeight];
break;
}
}
return price;
};
var shipping_price = addShippingPrice(8000);
console.log('amount', shipping_price);
use below code, in case of maximum weight goes beyond the defined weight in object, you can set default Value for such case.
shippingPrices = {
'economy': {
2000: 7,
5000: 9,
10000: 10,
20000: 15,
30000: 22
}
};
var addShippingPrice = function (weight) {
$.each(shippingPrices.economy, function (key, value) {
if (weight <= key) {
console.log(value);
return false;
}
});
};
addShippingPrice(700); // 7
addShippingPrice(8000); // 10
You shouldn't rely on Object key sequence here, since as stated in the MDN doc
The for...in statement iterates over the enumerable properties of an object, in arbitrary order.
What you can do is to prepare an array of key weights and sort it. This array can be used then for comparison with the given value. Once you define the corresponding key weight, you'll ease get the price
shippingPrices = {
'economy': {
2000: 7,
5000: 9,
10000: 10,
20000: 15,
30000: 22
}
};
var getShippingPrice = function(weight) {
var weights = [];
for( var maxWeight in shippingPrices.economy) {
weights.push(parseInt(maxWeight, 10));
}
weights.sort(function(a,b){
return a - b;
});
for (var i = 0; i < weights.length; i++) {
if (weights[i] >= weight) {
return shippingPrices.economy[weights[i]];
}
}
return 0; // or return Math.max.apply(null, weights);
};
console.log('19000 => ', getShippingPrice(19000));
console.log('5000 => ', getShippingPrice(5000));
console.log('5001 => ', getShippingPrice(5001));
BTW, don't give name such "add..." to function which should just return a value

Categories