I want to add validation for following java script associative array.
Here is my array structure
array = [
{ id: 1, remaining_amount: 30, total: 20 },
{ id: 1, remaining_amount: 30, total: 20 },
{ id: 2, remaining_amount: 50, total: 40 }
]
From the above array, for id 1, remaining amount is 30 but total amount is 40
So i want to add the validation that if total amount is grater then remaining amount for particular id then it will show me message.
Any Idea?
You can use reduce and filter
Use reduceto summarise the total. and use filter to get all those array that total is greater than remaining_amount
var array = [{ id: 1, remaining_amount: 30, total: 20 },{ id: 1, remaining_amount: 30, total: 20 },{ id: 2, remaining_amount: 50, total: 40 }];
var result = Object.values(array.reduce((c, v) => {
c[v.id] = c[v.id] || {id: v.id,remaining_amount: v.remaining_amount,total: 0};
c[v.id].total += v.total;
return c;
}, {})).filter(o => o.remaining_amount < o.total);
console.log(result);
You can use this code -
array.forEach(function(obj) {
if (obj.total > obj.remaining_amount)
console.log(`for id ${obj.id}, remaining amount is ${obj.remaining_amount} but total amount is ${obj.total}`);
});
Related
I am trying to find items that can be deleted, updated or added by passing updatedItems into a method, when there is an updated item with a start/end value the same (no overlaps), then the existing item will be removed and re-added with the updated start/end value.
const existingItems = [
{
id: '111',
start: 0,
end: 10,
cost: 100
},
{
id: '222',
start: 20,
end: 30,
cost: 200
},
];
const updatedItems = [
{
start: 0,
end: 9,
cost: 42
},
{
id: '222',
start: 20,
end: 30,
cost: 999
}
];
// expected result
const items = {
deleted: [
{
id: '111',
start: 0,
end: 10,
cost: 100
}
],
added: [
{
start: 0,
end: 9,
cost: 42
},
],
updated: [
{
id: '222',
start: 20,
end: 30,
cost: 999
}
]
};
There are many array functions available in JavaScript and so there are a lot of ways you can solve this. Ultimately it comes down to being able to iterate through both of your original objects and match up values to determine if something exists or not.
This certainly isn't the cleanest solution, but it produces the result you asked for given the input provided. Even if this is not exactly what you need, it should help point you in the right direction so you can learn.
const existingItems = [
{
id: '111',
start: 0,
end: 10,
cost: 100
},
{
id: '222',
start: 20,
end: 30,
cost: 200
},
];
const updatedItems = [
{
start: 0,
end: 9,
cost: 42
},
{
id: '222',
start: 20,
end: 30,
cost: 999
}
];
function _Merge(existing, updated) {
let newObj = {
deleted: [],
added: [],
updated: []
};
existingItems.forEach(item => {
if(updatedItems.filter(i => i["id"] == item["id"]).length > 0) {
newObj.updated = [...newObj.updated, item];
} else {
newObj.deleted = [...newObj.deleted, item];
}
});
updatedItems.forEach(item => {
if(existingItems.filter(i => i["id"] == item["id"]).length <= 0) {
newObj.added = [...newObj.added, item];
}
});
return newObj;
}
console.log(_Merge(existingItems, updatedItems));
This essentially takes the existing and updated items arrays and uses forEach() to loop and check which of the existing items needs to be updated or deleted. Then lastly it loops through the updated items array also using forEach() to determine which items need to be added.
In both cases it uses the filter() method to compare the current item's id to an array to see if there are any records that match.
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.
As you can see, the keys are now the name of the items and the corresponding value is another object consisting of two keys - quantity and price.
var itemsToBuy = {
milk: {
quantity : 5,
price: 20
},
bread: {
quantity : 2,
price: 15
},
potato: {
quantity : 3,
price: 10
}
}
I tried but I am getting only undefined output.
Want to get data such like :
['milk', 'bread', 'potato']
[20, 15, 10]
const object1 = {
milk: {
quantity : 5,
price: 20
},
bread: {
quantity : 2,
price: 15
},
potato: {
quantity : 3,
price: 10
}
}
console.log(Object.entries(object1).map(([key,value])=> value.price))
Solution
With Object.keys() you can get the keys of your Object as an array. -> ['milk', 'bread', 'potato']
With Object.entries() in combination with map() you can get the values of the price property as an array. -> [20, 15, 10]
Example:
var itemsToBuy = {
milk: {
quantity : 5,
price: 20
},
bread: {
quantity : 2,
price: 15
},
potato: {
quantity : 3,
price: 10
}
}
const keys = Object.keys(itemsToBuy);
const val = Object.entries(itemsToBuy).map((element)=> element[1].price)
console.log(keys);
console.log(val);
for names:
Object.keys(itemsToBuy) //["milk", "bread", "potato"]
and for prices:
Object.entries(itemsToBuy).map((el)=> el[1].price)//[20, 15, 10]
To get object keys you can use: Object.keys()
let keys = Object.keys(itemsToBuy) // ["milk", "bread", "potato"]
And for the nested values you can get 1st all values
let values = Object.values(itemsToBuy) // [{quantity : 5, price: 20}, {quantity : 2, price: 15}, {quantity : 3, price: 10}]
And then map to return the new array with elements you want to extract ex.price:
let price = values.map(value => value.price) // [20, 15, 10]
It's such an easy task, but somehow I'm stuck. I have an array of objects of product items that looks like this:
[{id: 1, price: 30, quantity: 2}, {id: 2, price: 20, quantity: 4}, {id: 3, price: 10, quantity: 2}]
I need to count the total price of all items, which should be: the price of a specific product multiplied by quantity and the same for previous products. Example: (30*2)+(20*4)+(10*2)
My code looks like this:
items.forEach(function (item) {
let sum = item.price * item.quantity;
console.log(sum);
});
The output looks like:
60
80
20
But I need to count the total which should be 160 and render it to the page and somehow I can't figure out the way to do that
The Array.prototype.reduce() method is best suited for operations like this (sum total).
In my answer below, sum is the accumulator and is initially set to 0. The accumulator is the value previously returned by the callback. The { price, quantity } is object destructering of the current value.
const sumTotal = arr =>
arr.reduce((sum, { price, quantity }) => sum + price * quantity, 0)
const data = [
{ id: 1, price: 30, quantity: 2 },
{ id: 2, price: 20, quantity: 4 },
{ id: 3, price: 10, quantity: 2 },
]
const total = sumTotal(data)
console.log(total) // 160
Here is a similar example.
You are close to getting the answer. I modified slightly your code and get the expected result. See below.
const items = [{id: 1, price: 30, quantity: 2}, {id: 2, price: 20, quantity: 4}, {id: 3, price: 10, quantity: 2}];
const sumItems = () => {
let sum = 0;
items.forEach(function(item) {
let calculation = item.price * item.quantity;
sum += calculation;
})
console.log(sum);
};
sumItems();
let items = [
{id: 1, price: 30, quantity: 2},
{id: 2, price: 20, quantity: 4},
{id: 3, price: 10, quantity: 2}
]
let total = items.reduce((sum,item) => sum + item.price * item.quantity, 0);
console.log(total);
var products =[{id: 1, price: 30, quantity: 2}, {id: 2, price: 20, quantity: 4}, {id: 3, price: 10, quantity: 2}]
console.log(products.map(x=> x.price*x.quantity).reduce((a, b) => a + b, 0))
If you can use an external library, I suggest using the sumBy method from lodash library
Example:
_.sumBy(items, function(item) { return item.price * item.quantity; });
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);