Javascript Filter an Array to give subset from two Range Parameters - javascript

How do I filter an array two give me the subset created by overlap of two ranges?
For example, suppose Here's my array with a bunch of objects:
const list = [{
id: 1,
price: "10",
weight: "19.45"
},{
id: 2,
price: "14",
weight: "27.8"
},{
id: 3,
price: "45",
weight: "65.7"
},{
id: 4,
price: "37",
weight: "120.5"
},{
id: 5,
price: "65",
weight: "26.9"
},{
id: 6,
price: "120",
weight: "19.3"
},{
id: 7,
price: "20",
weight: "45.7"
}]
Now I want to filter the above array of objects based on a range for two parameters price and weight.
let range = {
startPrice: 15,
endPrice: 60,
startWeight: 22.0,
endWeight: 70.5,
}
I want to filter my list with these range parameters which will return me an array with a subset of objects satisfying both the filter ranges. Hence, the output array should be:
filtered = [{
id: 3,
price: "45",
weight: "65.7"
},{
id: 7,
price: "20",
weight: "45.7"
}]
Because items with id: 3 and id: 5 satisfy the subset of both of the two ranges. How should my list.filter() function look like? Any help is greatly appreciated, thank you.

Note: I've used parseFloat because values are stored as a String. There are other ways to get a Number out of a String.
var list = [{"id":1,"price":"10","weight":"19.45"},{"id":2,"price":"14","weight":"27.8"},{"id":3,"price":"45","weight":"65.7"},{"id":4,"price":"37","weight":"120.5"},{"id":5,"price":"65","weight":"26.9"},{"id":6,"price":"120","weight":"19.3"},{"id":7,"price":"20","weight":"45.7"}];
var range = {
startPrice: 15,
endPrice: 60,
startWeight: 22.0,
endWeight: 70.5
};
var filtered=list.filter(
element=> {
var elementprice=parseFloat(element.price);
var elementweight=parseFloat(element.weight);
if(
elementprice>=range.startPrice &&
elementprice<=range.endPrice &&
elementweight>=range.startWeight &&
elementweight<=range.endWeight
) {
return true;
}
return false;
}
);
console.log(filtered);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You mean 3 and 7
Also you need to either remove the quotes or cast to number. Note a filter will expect a true or false to a Boolean test is enough. No if or else needed
const list = [{ id: 1, price: "10", weight: "19.45" }, { id: 2, price: "14", weight: "27.8" }, { id: 3, price: "45", weight: "65.7" }, { id: 4, price: "37", weight: "120.5" }, { id: 5, price: "65", weight: "26.9" }, { id: 6, price: "120", weight: "19.3" }, { id: 7, price: "20", weight: "45.7" }];
let range = { startPrice: 15, endPrice: 60, startWeight: 22.0, endWeight: 70.5, }
const res = list.filter(item =>
+item.price >= range.startPrice &&
+item.price <= range.endPrice &&
+item.weight >= range.startWeight &&
+item.weight <= range.endWeight);
console.log(res);

Related

How can I see if Object Array has elements in Another Object Array?

Is there a way to tell if an object array has any common elements to another object array, and what that object intersect is? (like a Contains function). In the example below,ProductId3 in Object Array 1, is also contained in Object Array 2.
I'm thinking of using a double for loop . However is there a more efficient/optimal way, or shorthand ecma or lodash function?
We are checking all object members, not just ProductId.
array1.forEach(arr1 => {
array2.forEach(arr2 => {
if (arr1.productId === arr2.productId &&
arr1.productName === arr2.productName ...
Object Array 1:
[
{
ProductId: 50,
ProductName: 'Test1',
Location: 77,
Supplier: 11,
Quantity: 33
},
{
ProductId: 3,
ProductName: 'GHI',
Location: 1,
Supplier: 4,
Quantity: 25
}
]
Object Array 2:
[
{
ProductId: 1,
ProductName: 'ABC',
Location: 3,
Supplier: 4,
Quantity: 52
},
{
ProductId: 2,
ProductName: 'DEF',
Location: 1,
Supplier: 2,
Quantity: 87
},
{
ProductId: 3,
ProductName: 'GHI',
Location: 1,
Supplier: 4,
Quantity: 25
},
{
ProductId: 4,
ProductName: 'XYZ',
Location: 5,
Supplier: 6,
Quantity: 17
}
]
Resources:
How to determine if Javascript array contains an object with an attribute that equals a given value?
Javascript: Using `.includes` to find if an array of objects contains a specific object
Is there a way to tell if an object array has any common elements to another object array ? - Yes you can achieve this with the help of Array.some() method. It returns true if, in the array, it finds an element for which the provided function returns true; otherwise it returns false.
const array1 = [{
ProductId: 50,
ProductName: 'Test1',
Location: 77,
Supplier: 11,
Quantity: 33
}, {
ProductId: 3,
ProductName: 'GHI',
Location: 1,
Supplier: 4,
Quantity: 25
}];
const array2 = [{
ProductId: 1,
ProductName: 'ABC',
Location: 3,
Supplier: 4,
Quantity: 52
}, {
ProductId: 2,
ProductName: 'DEF',
Location: 1,
Supplier: 2,
Quantity: 87
}, {
ProductId: 3,
ProductName: 'GHI',
Location: 1,
Supplier: 4,
Quantity: 25
}, {
ProductId: 4,
ProductName: 'XYZ',
Location: 5,
Supplier: 6,
Quantity: 17
}];
const isCommonProducts = array2.some(({ ProductId }) => array1.map(obj => obj.ProductId).includes(ProductId));
console.log(isCommonProducts);
Update : As per the author comment, we have to check all the properties of an object. Hence, we can achieve that by comparing the JSON string by converting the object into a string.
Live Demo :
const array1 = [{
ProductId: 50,
ProductName: 'Test1',
Location: 77,
Supplier: 11,
Quantity: 33
}, {
ProductId: 3,
ProductName: 'GHI',
Location: 1,
Supplier: 4,
Quantity: 25
}];
const array2 = [{
ProductId: 1,
ProductName: 'ABC',
Location: 3,
Supplier: 4,
Quantity: 52
}, {
ProductId: 2,
ProductName: 'DEF',
Location: 1,
Supplier: 2,
Quantity: 87
}, {
ProductId: 3,
ProductName: 'GHI',
Location: 1,
Supplier: 4,
Quantity: 25
}, {
ProductId: 4,
ProductName: 'XYZ',
Location: 5,
Supplier: 6,
Quantity: 17
}];
const getFilteredProducts = array2.filter(productObj => JSON.stringify(array1).indexOf(JSON.stringify(productObj)) !== -1);
console.log(getFilteredProducts);
If we can assume that each array's elements (we will call them sub-dictionaries) contain exactly the same keys in the same order, then this is my idea:
Convert each array into a new array whose elements are the JSON representations of the original sub-dictionaries values. This is an o(N) operation performed twice.
Of the new, converted arrays find the shortest one. Convert the other into a set. This is also o(N).
For each element of the shorter converted array, check to see if the set contains this value. This is also o(N).
let arr1 = [
{
ProductId: 50,
ProductName: 'Test1',
Location: 77,
Supplier: 11,
Quantity: 33
},
{
ProductId: 3,
ProductName: 'GHI',
Location: 1,
Supplier: 4,
Quantity: 25
}
];
let arr2 = [
{
ProductId: 1,
ProductName: 'ABC',
Location: 3,
Supplier: 4,
Quantity: 52
},
{
ProductId: 2,
ProductName: 'DEF',
Location: 1,
Supplier: 2,
Quantity: 87
},
{
ProductId: 3,
ProductName: 'GHI',
Location: 1,
Supplier: 4,
Quantity: 25
},
{
ProductId: 4,
ProductName: 'XYZ',
Location: 5,
Supplier: 6,
Quantity: 17
}
];
// Convert each sub-array's values to JSON string:
let arr1New = arr1.map(function(arr) {return JSON.stringify(Object.values(arr));});
let arr2New = arr2.map(function(arr) {return JSON.stringify(Object.values(arr));});
// Find shortest array of JSON strings:
const l1 = arr1New.length;
const l2 = arr2New.length;
// enumerate shortest list
let list, set, l, arr;
if (l1 <= l2) {
list = arr1New;
set = new Set(arr2New);
l = l1;
arr = arr1;
}
else {
list = arr2New;
set = new Set(arr1New);
l = l2;
arr = arr2;
}
for(let i = 0; i < l; i++) {
if (set.has(list[i])) {
console.log(arr[i]);
}
}
Update
If the sub-dictionary keys are not necessarily in order, then we have to create new sub-dictionaries from these where the keys are in order:
// Create function to create new dictionaries sorted by keys
function sort_dict(d) {
items = Object.keys(d).map(function(key) {
return [key, d[key]];
});
items.sort(function(first, second) {
return first[0] < second[0] ? -1 : (first[0] > second[0] ? 1 : 0);
});
sorted_dict = {};
items.forEach(function(x) {
sorted_dict[x[0]] = x[1];
});
return(sorted_dict);
}
// And then we have these modified lines:
// Convert each sub-array's values to JSON string:
let arr1New = arr1.map(function(arr) {return JSON.stringify(Object.values(sort_dict(arr)));});
let arr2New = arr2.map(function(arr) {return JSON.stringify(Object.values(sort_dict(arr)));});
Modified Code
let arr1 = [
{
ProductId: 50,
ProductName: 'Test1',
Location: 77,
Supplier: 11,
Quantity: 33
},
{
ProductName: 'GHI',
Location: 1,
Supplier: 4,
Quantity: 25,
ProductId: 3 // Not in the same order as the others
}
];
let arr2 = [
{
ProductId: 1,
ProductName: 'ABC',
Location: 3,
Supplier: 4,
Quantity: 52
},
{
ProductId: 2,
ProductName: 'DEF',
Location: 1,
Supplier: 2,
Quantity: 87
},
{
ProductId: 3,
ProductName: 'GHI',
Location: 1,
Supplier: 4,
Quantity: 25
},
{
ProductId: 4,
ProductName: 'XYZ',
Location: 5,
Supplier: 6,
Quantity: 17
}
];
function sort_dict(d) {
items = Object.keys(d).map(function(key) {
return [key, d[key]];
});
items.sort(function(first, second) {
return first[0] < second[0] ? -1 : (first[0] > second[0] ? 1 : 0);
});
sorted_dict = {};
items.forEach(function(x) {
sorted_dict[x[0]] = x[1];
});
return(sorted_dict);
}
// Convert each sub-array's values to JSON string:
let arr1New = arr1.map(function(arr) {return JSON.stringify(Object.values(sort_dict(arr)));});
let arr2New = arr2.map(function(arr) {return JSON.stringify(Object.values(sort_dict(arr)));});
// Find shortest array of JSON strings:
const l1 = arr1New.length;
const l2 = arr2New.length;
// enumerate shortest list
let list, set, l, arr;
if (l1 <= l2) {
list = arr1New;
set = new Set(arr2New);
l = l1;
arr = arr1;
}
else {
list = arr2New;
set = new Set(arr1New);
l = l2;
arr = arr2;
}
for(let i = 0; i < l; i++) {
if (set.has(list[i])) {
console.log(arr[i]);
}
}
For a simple yet reasonably fast solution, you can (1) use a Set of productIds from the first array, then (2) filter the second array based on the ids from the first one, this you only have to go over each array once O(n).
let arr1 = [
{
ProductId: 50,
ProductName: "Test1",
Location: 77,
Supplier: 11,
Quantity: 33,
},
{
ProductId: 3,
ProductName: "GHI",
Location: 1,
Supplier: 4,
Quantity: 25,
},
];
let arr2 = [
{
ProductId: 1,
ProductName: "ABC",
Location: 3,
Supplier: 4,
Quantity: 52,
},
{
ProductId: 2,
ProductName: "DEF",
Location: 1,
Supplier: 2,
Quantity: 87,
},
{
ProductId: 3,
ProductName: "GHI",
Location: 1,
Supplier: 4,
Quantity: 25,
},
{
ProductId: 4,
ProductName: "XYZ",
Location: 5,
Supplier: 6,
Quantity: 17,
},
];
const getCommonItems = (arr1, arr2) => {
let firstIdSet = new Set(arr1.map((product) => product.ProductId)); //1
return arr2.filter((product) => firstIdSet.has(product.ProductId)); //2
};
console.log(getCommonItems(arr1, arr2));
If you want a deep equality comparison(for nested objects or for all (key, value) pairs), I would suggest a slightly better approach which is using the base64 encoding/decoding to improve on comparison performance.
So my approach is to:
merge the arrays and convert the object to base64 strings.
Group the recurrences together
Filter on duplicates
revert the base64 strings into their original object.
const convertObjToBase64 = o => btoa(JSON.stringify(o));
const convertBase64ToObj = str => JSON.parse(atob(str));
const arrayToObjCount = arr => arr.reduce((res, v) => {
res[v] = (res[v] ?? 0) + 1;
return res;
}, {});
const findDuplicateObjectsInMultipleArrays = (...arrays) => {
const base64Array = Array.from(arrays.flat(), convertObjToBase64);
const objCount = arrayToObjCount(base64Array);
const duplicates = Object.entries(objCount).reduce((prev, [k, v]) => {
if (v > 1) {
prev.push(convertBase64ToObj(k));
}
return prev;
}, []);
return duplicates;
}
let arr1 = [{
ProductId: 50,
ProductName: 'Test1',
Location: {
LocationId: 77,
LocationName: 'Location 77'
},
Supplier: 11,
Quantity: 33
},
{
ProductId: 3,
ProductName: 'GHI',
Location: {
LocationId: 1,
LocationName: 'Location 1'
},
Supplier: 4,
Quantity: 25
}
];
let arr2 = [{
ProductId: 1,
ProductName: 'ABC',
Location: {
LocationId: 3,
LocationName: 'Location 3'
},
Supplier: 4,
Quantity: 52
},
{
ProductId: 2,
ProductName: 'DEF',
Location: {
LocationId: 1,
LocationName: 'Location 1'
},
Supplier: 2,
Quantity: 87
},
{
ProductId: 3,
ProductName: 'GHI',
Location: {
LocationId: 1,
LocationName: 'Location 1'
},
Supplier: 4,
Quantity: 25
},
{
ProductId: 4,
ProductName: 'XYZ',
Location: {
LocationId: 5,
LocationName: 'Location 5'
},
Supplier: 6,
Quantity: 17
}
];
let arr3 =[
{
ProductId: 2,
ProductName: 'DEF',
Location: {
LocationId: 1,
LocationName: 'Location 1'
},
Supplier: 2,
Quantity: 87
},
{
ProductId: 3,
ProductName: 'GHI',
Location: {
LocationId: 2,
LocationName: 'Location 2'
},
Supplier: 4,
Quantity: 25
},
{
ProductId: 4,
ProductName: 'XYZ',
Location: {
LocationId: 6,
LocationName: 'Location 5'
},
Supplier: 6,
Quantity: 17
}
];
console.log(findDuplicateObjectsInMultipleArrays(arr1, arr2, arr3));
I will post two solutions:
First Solution is readable one
Code is not 100% performance optimized, but it is readable and elegant.
Playground link with working code
First, we need a method that compares two objects of any type. The method compares the first-level properties, so if we have nested object properties, it will compare them by reference.
const areTheSame = (a: any, b: any) => {
const objAProps = Object.keys(a).filter(key => typeof a[key] !== "function")
const objBProps = Object.keys(b).filter(key => typeof b[key] !== "function")
if (objAProps.length !== objBProps.length) {
return false;
}
return objAProps.every((propName) => a[propName] === b[propName]);
}
And then we can implement readable intersect method which will work for any array types:
const getIntersection = (array1: Array<any>, array2: Array<any>) => {
return array1.filter(a1Item => array2.some(a2Item => areTheSame(a1Item, a2Item)));
}
The Second solution is performance-oriented, its drawback is that it is not so readable
First, we calculate the has for all objects, then within a single forEach loop we can identify the intersection based on that Hash. I have used md5, but any hash algorithm or library can be used.
Hers is stack blitz link playground. It can be run, ignore the import error.
const getArrayIntersection = (
firstArray: Array<any>,
secondArray: Array<any>
) => {
const array1Hashed = firstArray.map((i) => md5(JSON.stringify(i)));
const array2Set = new Set(secondArray.map((i) => md5(JSON.stringify(i))));
const result: Array<any> = [];
array1Hashed.forEach((itemHash, index) => {
if (array2Set.has(itemHash)) {
result.push(firstArray[index]);
}
});
return result;
};
Just to piggyback #Rohìt Jíndal, you can check if an array has a specific object like so:
const resultObj = arr1.filter(obj => obj.id=== "whatever" && obj.productname == "whatever") // ETC ETC

return specific properties from array of objects into new object [duplicate]

This question already has answers here:
From an array of objects, extract value of a property as array
(24 answers)
Closed 2 years ago.
I've an array of objects, what I want is to copy all the objects from that, but with specific properties not all the properties.
like for example I've this object named cart
cart = [
{ id: 1, name: 'makeup', price: 200, qty: 1 },
{ id: 2, name: 'gloves', price: 300, qty: 2 },
{ id: 3, name: 'sanitizer', price: 400, qty: 3 },
{ id: 4, name: 'book', price: 100, qty: 1 },
{ id: 5, name: 'hairs', price: 250, qty: 4 },
{ id: 6, name: 'soap', price: 50, qty: 5 },
{ id: 7, name: 'shampoo', price: 700, qty: 1 },
]
and I want to extract only the id and qty attributes to a new array of objects.
How do I do this.
I already tried
products=cart.map(prod=>prod.id, prod.qty)
but this doesn't seems to be working.
Thanks in advance to helping hands
You can Array.prototype.map() or Array.prototype.reduce() over the entire array and only return the values you want.
const cart = [
{ id: 1, name: 'makeup', price: 200, qty: 1 },
{ id: 2, name: 'gloves', price: 300, qty: 2 },
{ id: 3, name: 'sanitizer', price: 400, qty: 3 },
{ id: 4, name: 'book', price: 100, qty: 1 },
{ id: 5, name: 'hairs', price: 250, qty: 4 },
{ id: 6, name: 'soap', price: 50, qty: 5 },
{ id: 7, name: 'shampoo', price: 700, qty: 1 },
]
console.log( cart.map( elem => ({id:elem.id, qty : elem.qty})))
You need to iterate and return only the desired properties.
cart = [
{ id: 1, name: 'makeup', price: 200, qty: 1 },
{ id: 2, name: 'gloves', price: 300, qty: 2 },
{ id: 3, name: 'sanitizer', price: 400, qty: 3 },
{ id: 4, name: 'book', price: 100, qty: 1 },
{ id: 5, name: 'hairs', price: 250, qty: 4 },
{ id: 6, name: 'soap', price: 50, qty: 5 },
{ id: 7, name: 'shampoo', price: 700, qty: 1 },
]
const newcart = cart.map(item => {
return {id: item.id, qty: item.qty}
});
console.log(newcart)
You almost had it correct.
When using arrow functions without the brackets, whatever is put after the arrow function is returned.
So your code could look like this:
const products = cart.map(({ id, qty }) => ({ id, qty }));
We destructure the object in the arrow function and return it as a new object.
Make sure to have the round brackets around the value that you return. Otherwise javascript will see it as the body of a function instead of an object that is returned.
You can update your .map() method like this to acheive the desired result:
const cart = [{id:1,name:"makeup",price:200,qty:1},{id:2,name:"gloves",price:300,qty:2},{id:3,name:"sanitizer",price:400,qty:3},{id:4,name:"book",price:100,qty:1},{id:5,name:"hairs",price:250,qty:4},{id:6,name:"soap",price:50,qty:5},{id:7,name:"shampoo",price:700,qty:1}];
const products = cart.map(({id, qty}) => ({ id, quantity: qty }))
console.log(products)
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to sum multiple different objects in an array using Vuejs?

I am getting started with Vue. I am struggling to calculate the sum of different elements in an object of an array.
My array looks like this:
sites: [{
sku: 10001,
name: "Product A",
totalPrice: '',
values: [{
price: 10,
discount: 5,
color: "red"
},
{
price: 15,
discount: 8,
color: "black"
}]
},
{
sku: 10002,
name: "Product B",
totalPrice: '',
values: [{
price: 13,
discount: 3,
color: "purple"
},
{
price: 20,
discount: 5,
color: "green"
}]
}]
I am trying to sum the price and set it to totalPrice. So the array will change totalPrice as below:
sku: 10001,
name: "Product A",
totalPrice: 25,
sku: 10002,
name: "Product B",
totalPrice: 33,
I believe I need to use something like the below to sum them, however I cannot figure out how to do this!
computed: {
total(){ return this.sites.reduce( (total, item) => item.values. price + total ,0);}
},
How do I calculate the sum of the price and set it as the totalPrice?
I have traveled SO and find similar threads however nothing that I can get to work with my issue.
computed: {
total() {
let newojv = []
sites.forEach((item, _) => {
let s = item.values.map((items2, _) => {
return items2.price;
})
let sum = s.reduce((a, b) => a + b);
newojv.push({
sku: item.sku,
name: item.name,
totalPrice: sum
});
});
return newojv;
}
}
First for Each of the array of objects below
{
sku: 10001,
name: "Product A",
totalPrice: '',
values: [{
price: 10,
discount: 5,
color: "red"
},
{
price: 15,
discount: 8,
color: "black"
}
]
}
And then for Each of the array of objects below
values: [{
price: 10,
discount: 5,
color: "red"
},
{
price: 15,
discount: 8,
color: "black"
}
]
We take a we map the array to get the values of the price, which is 10,15. Then we reduce the array, add it and then push it.
let sum = s.reduce((a, b) => a + b);
newojv.push({
sku: item.sku,
name: item.name,
totalPrice: sum
});
A working example can be
let sites = [{
sku: 10001,
name: "Product A",
totalPrice: '',
values: [{
price: 10,
discount: 5,
color: "red"
},
{
price: 15,
discount: 8,
color: "black"
}
]
}, {
sku: 10002,
name: "Product B",
totalPrice: '',
values: [{
price: 13,
discount: 3,
color: "purple"
},
{
price: 20,
discount: 5,
color: "green"
}
]
}]
let newojv = []
sites.forEach((item, _) => {
let s = item.values.map((items2, _) => {
return items2.price;
})
let sum = s.reduce((a, b) => a + b);
newojv.push({
sku: item.sku,
name: item.name,
totalPrice: sum
});
});
console.log(newojv)

ES6 Nested Grouping with Sum

I have an array like this:
[{
id: 1,
amount: 10,
date: '21/01/2017'
},{
id: 1,
amount: 10,
date: '21/01/2017'
},{
id: 1,
amount: 30,
date: '22/01/2017'
},{
id: 2,
amount: 10,
date: '21/01/2017'
},]
And I would like this to output like:
{
'21/01/2017': {
1: {
amount: 20
},
2: {
amount: 10
}
},
'22/01/2017': {
1: {
amount: 30
}
}
}
Essentially grouping by data, nested grouping by id, whilst summing the relevant amounts.
So far I have tried using reduce, and have looked at lodash functions but have been unsuccessful. Reduce makes it easy to group by and sum by one prop, but I cannot find an elegant way to create the second level. I have created the a sandbox to demonstrate:
https://codesandbox.io/s/woj9xz6nq5
const dataToConsolidate = [{
id: 1,
amount: 10,
date: '21/01/2017'
}, {
id: 1,
amount: 10,
date: '21/01/2017'
}, {
id: 1,
amount: 30,
date: '22/01/2017'
}, {
id: 2,
amount: 10,
date: '21/01/2017'
},]
export const consolidate = (data) => {
const result = data.reduce(function (res, obj) {
(!(obj.date in res)) ?
res.__array.push(res[obj.date] = obj) :
res[obj.date].amount += obj.amount;
return res;
}, { __array: [] });
return result;
};
console.log(consolidate(dataToConsolidate))
You could take the object as hash table and add the properties with a default style.
var array = [{ id: 1, amount: 10, date: '21/01/2017' }, { id: 1, amount: 10, date: '21/01/2017' }, { id: 1, amount: 30, date: '22/01/2017' }, { id: 2, amount: 10, date: '21/01/2017' }],
result = {};
array.forEach(function (o) {
result[o.date] = result[o.date] || {};
result[o.date][o.id] = result[o.date][o.id] || { amount: 0 };
result[o.date][o.id].amount += o.amount;
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here's a relatively ES6-y solution using reduce:
const initial = [{ id: 1, amount: 10, date: '21/01/2017' }, { id: 1, amount: 10, date: '21/01/2017' }, { id: 1, amount: 30, date: '22/01/2017' }, { id: 2, amount: 10, date: '21/01/2017' }];
const parse = obj => obj.reduce((final, { date, id, amount }) => {
let group = final[date] = final[date] || {};
group[id] = group[id] || { amount: 0 };
group[id].amount += amount;
return final;
}, {});
const final = parse(initial);
console.log(final);
You'll want to add appropriate logic to handle missing/erroneous date, id, or amount keys.
As a fan of the library Ramda (disclaimer: I'm one of the authors), I might well use it to make everything a bit more explicit:
const {pipe, groupBy, prop, map, pluck, sum} = R
const data = [
{"amount": 10, "date": "21/01/2017", "id": 1},
{"amount": 10, "date": "21/01/2017", "id": 1},
{"amount": 30, "date": "22/01/2017", "id": 1},
{"amount": 10, "date": "21/01/2017", "id": 2}
]
const consolidate = pipe(
groupBy(prop('date')),
map(groupBy(prop('id'))),
map(map(pluck('amount'))),
map(map(sum))
)
console.log(consolidate(data))
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
Of course using a library just to solve this problem is simply overkill, when something like the solution from #NinaSholz does just fine. But if you find several places where it could help, it might be worth looking into something like that.
you can do it thru _.groupBy:
const res = _.chain(data)
.groupBy('date')
.mapValues(dateObj => _.chain(dateObj)
.groupBy('id')
.mapValues(idObj => ({ amount: _.sumBy(idObj, 'amount') }))
.value()
)
.value();

Efficient use of Map, Reduce, or filter to find information from given array of objects

ordersList = [
[{
id: 1,
name: "chicken Burger",
sellPrice: 20,
buyPrice: 15,
qty: 5
}, {
id: 2,
name: "Beef Burger",
sellPrice: 22,
buyPrice: 16,
qty: 3
}, {
id: 3,
name: "Chicken Sandwich",
sellPrice: 15,
buyPrice: 13,
qty: 2
}
],
[{
id: 1,
name: "Beef Burger",
sellPrice: 22,
buyPrice: 16,
qty: 2
}, {
id: 2,
name: "Chicken Sandwich",
sellPrice: 15,
buyPrice: 13,
qty: 2
}
],
[{
id: 1,
name: "Chicken Sandwich",
sellPrice: 15,
buyPrice: 13,
qty: 20
}, {
id: 1,
name: "Beef Burger",
sellPrice: 15,
buyPrice: 13,
qty: 10
}
]
]
A new Objects should be created with item-title(key), (Total Quantity,
Total BuyPrice, and Total SellPrice)(value) from the given JSON DATA.The purpose of this question is to find how list comprehension, immutable state,functional style can be used to find the data given below.
example-{ 'chicken Burger': { totalQty: 5, buySumPrice: 75, sellSumPrice: 100 },
'Beef Burger': { totalQty: 15, buySumPrice: 210, sellSumPrice: 260 },
'Chicken Sandwich': { totalQty: 24, buySumPrice: 312, sellSumPrice: 360 } }
function getAll() {
var total = {};
ordersList.map(function(orders) {
orders.map(function(order) {
total[order.name] = total[order.name] ? ({
qty: (total[order.name]).qty + order.qty,
buySumPrice:(total[order.name]).buySumPrice + order.buyPrice*order.qty ,
sellSumPrice: (total[order.name]).sellSumPrice + order.sellPrice*order.qty
}) : ({
qty: order.qty,
buySumPrice: order.buyPrice*order.qty,
sellSumPrice: order.sellPrice*order.qty
});
});
});
return total;
}
Is it possible to removing the outer total {} by returning the constructed array from the maps. Also using reduce to do the calculation for summation.
You have a real bear of a problem here. I'm going to solve it using ES6 because it has a couple of tools that makes this kind of thing much easier. If you need the ES5, copy/paste this into babel or add a build step to your application.
const getData = ordersList => {
let merge = ({totalQty=0, buySumPrice=0, sellSumPrice=0}={}, {qty, buyPrice, sellPrice}) => ({
totalQty: totalQty + qty,
buySumPrice: buySumPrice + (qty * buyPrice),
sellSumPrice: sellSumPrice + (qty * sellPrice)
});
return ordersList.reduce((ys, xs) => {
xs.forEach(x => Object.assign(ys, {[x.name]: merge(ys[x.name], x)}));
return ys;
}, {});
};
let answer = getData(ordersList);
console.log(JSON.stringify(answer, null, "\t"));
Output
{
"chicken Burger": {
"totalQty": 5,
"buySumPrice": 75,
"sellSumPrice": 100
},
"Beef Burger": {
"totalQty": 15,
"buySumPrice": 210,
"sellSumPrice": 260
},
"Chicken Sandwich": {
"totalQty": 24,
"buySumPrice": 312,
"sellSumPrice": 360
}
}
Remarks:
The ugliest part of this problem is that the Arrays are nested. If you could afford to flatten the Array(Array(Object{})) structure to Array(Object{}), it would be a much nicer problem. However, that would require iterating through your list twice. For reasonably large inputs, that computational overhead could be a deal breaker.

Categories