Filter array in an array - javascript

I have a material with a certain ID number and an array of products that contain an array of materials they consist of. I need to filter out all the products that include that specific material (all the products that have that ID number inside their materials array).
Is there a prompt way to do that with ES6 syntax?
E.g
const myMaterialId = 100
const productsArray = [
{
name: products,
materials: [
{id: 100, amount: 30},
{id: 102, amount: 20},
],
},
{
name: product2,
materials: [
{id: 115, amount: 25},
{id: 120, amount: 50},
],
},
{
name: product2,
materials: [
{id: 100, amount: 35},
{id: 120, amount: 50},
{id: 150, amount: 10},
],
}
];```

You can use the filter function:
var filteredProductsArray = productsArray.filter(product => product.materials.filter(material => material.id === myMaterialId).length > 0);
This will filter all products by filtering their materials to see if the materials array has a material with your material id.

https://jsfiddle.net/8r31zdav/ u can use filter and find method
var result= productsArray.filter(x=>x.materials.find(y=>y.id==myMaterialId));
and also your object is invalid. value of name attribute is string so u need to write it in ""
const productsArray = [
{
name: "products",
materials: [
{id: 100, amount: 30},
{id: 102, amount: 20},
],
},
{
name: "product3",
materials: [
{id: 115, amount: 25},
{id: 120, amount: 50},
],
},
{
name: "product2",
materials: [
{id: 100, amount: 35},
{id: 120, amount: 50},
{id: 150, amount: 10},
],
}
];

Related

Match spanish words replace method

this functions searchs names or categories of this array of objects, i need to ignore spanish letters with 'acento' (for example: i need to match 'Taragüí' if i write taragui), i solve this with the string replace() method, my question: Is there a way to solve this with some unicode method? Thanks in advance.
var fromDB = [
{id: 1, name: 'Almendras', category: 'Frutos secos', price: 25, amount: 0, description: 'asd'},
{id: 2, name: 'Nueces', category: 'Frutos secos', price: 10, amount: 0, description: 'asd'},
{id: 3, name: 'Mermelada', category: 'Jam', price: 15, amount: 0, description: 'asd'},
{id: 4, name: 'Alfajor', category: 'Sweet', price: 20, amount: 0, description: 'asd'},
{id: 5, name: 'Queso', category: 'UwU', price: 45, amount: 0, description: 'asd'},
{id: 6, name: 'Arandanos', category: 'Fruta', price: 50, amount: 0, description: 'asd'},
{id: 7, name: 'Maracuya', category: 'Fruta', price: 50, amount: 0, description: 'asd'},
{id: 8, name: 'Chocolate', category: 'Sweet', price: 50, amount: 0, description: 'asd'},
{id: 9, name: 'Mascarpone', category: 'UwU', price: 50, amount: 0, description: 'asd'},
{id: 9, name: 'Taragüí', category: 'UwU', price: 50, amount: 0, description: 'asd'}
];
const input = document.querySelector('input');
input.addEventListener('input', updateValue);
function updateValue(e) {
realTimeInputValue = e.target.value.toLowerCase();
let productsMatch = fromDB.filter(x => x.name.toLowerCase().replace('á', 'a').replace('é', 'e').replace('í', 'i').replace('ó', 'o').replace('ú', 'u').replace('ü', 'u').includes(realTimeInputValue))
if(productsMatch.length){
console.log(productsMatch)
} else {
let categoriesMatch = fromDB.filter(x => x.category.toLowerCase().includes(realTimeInputValue))
console.log(categoriesMatch);
}
}
<input type="text" placeholder="Enter some text" name="name"/>

JS How to get matching id between 2 array object

How do I get 2 matching id between 2 array object using javascript?
// Array 1
const array1 = [
{id: 1, name: 'milla'},
{id: 2, name: 'alice'}
]
// Array 2
const array2 = [
{id: 3, name: 'bobba', height: '170cm', age: 22},
{id: 2, name: 'alice', height: '169cm', age: 21},
{id: 1, name: 'milla', height: '171cm', age: 24},
{id: 4, name: 'ricky', height: '168cm', age: 32},
]
the expected output is to returned array of object of Array2 that mached with id's on array1
// expected result
[
{id: 2, name: 'alice', height: '169cm', age: 21},
{id: 1, name: 'milla', height: '171cm', age: 24},
]
You could filter and look if the same id exists.
const
array1 = [{ id: 1, name: 'milla' }, { id: 2, name: 'alice' }],
array2 = [{ id: 3, name: 'bobba', height: '170cm', age: 22 }, { id: 2, name: 'alice', height: '169cm', age: 21 }, { id: 1, name: 'milla', height: '171cm', age: 24 }, { id: 4, name: 'ricky', height: '168cm', age: 32 }],
hash = array1.reduce((r, { id }) => (r[id] = true, r), {}),
filtered = array2.filter(({ id }) => hash[id]);
console.log(filtered);
The most efficient way to do this is to generate a map of the IDs in array1 and then filter array2 against those IDs, like so:
let array1 = [{ id: 1, name: 'milla' }, { id: 2, name: 'alice' }];
let array2 = [{ id: 3, name: 'bobba', height: '170cm', age: 22 }, { id: 2, name: 'alice', height: '169cm', age: 21 }, { id: 1, name: 'milla', height: '171cm', age: 24 }, { id: 4, name: 'ricky', height: '168cm', age: 32 }];
let idMap = array1.reduce((res, curr) => (res[curr.id] = true, res), {});
let filtered = array2.filter((item) => idMap[item.id]);
console.log(filtered)
Honestly, this is basic JS, but anyway, here's the solution:
const array1 = [
{id: 1, name: 'milla'},
{id: 2, name: 'alice'}
]
// Array 2
const array2 = [
{id: 3, name: 'bobba', height: '170cm', age: 22},
{id: 2, name: 'alice', height: '169cm', age: 21},
{id: 1, name: 'milla', height: '171cm', age: 24},
{id: 4, name: 'ricky', height: '168cm', age: 32},
]
const map = array1.reduce((a, c) => ({ ...a, [c.id]: true }), {});
const array3 = array2.filter(item => map[item.id]);
console.log(array3);

Grouping and hierarchical mapping with lodash

I'm trying to transform some data by using Lodash groupBy and map. Here is sample data:
var data = [
{name: 'x', qty: 0, rate: 10},
{name: 'x', qty: 10, rate: 2},
{name: 'y', qty: 5, rate: 20},
{name: 'y', qty: 55, rate: 11}]
I need that data in the format:
var data = [
{name: 'x', pricing: [{qty: 0, rate: 10}, {qty: 10, rate: 2}]},
{name: 'y', pricing: [{qty: 5, rate: 20}, {qty: 55, rate: 11}]}]
The following is my attempt:
var m = _.chain(data)
.groupBy(data, 'name')
.map( function(i) {
return {
name: _.first(i).name,
pricing: _.map(i, function(r) {
return _.pick(r, ['qty', 'rate'])
})
}
})
This produces
[{
"name": "x",
"pricing": [
{"qty": 0, "rate": 10},
{"qty": 10, "rate": 2},
{"qty": 5,"rate": 20},
{"qty": 55,"rate": 11}]
}]
I've been unable to figure out what I'm doing wrong. Maybe this isn't even valid and there is a better way?
You need to map new object and get the picked values.
var data = [{ name: 'x', qty: 0, rate: 10 }, { name: 'x', qty: 10, rate: 2 }, { name: 'y', qty: 5, rate: 20 }, { name: 'y', qty: 55, rate: 11 }],
result = _(data)
.groupBy('name')
.map((pricing, name) => ({
name,
pricing: _.map(pricing, _.partialRight(_.pick, ['qty', 'rate']))
}))
.value();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
You don't need to use lodash for this - standard Javascript array methods work just fine. Reduce into an object indexed by name, then get that object's values:
var data = [
{name: 'x', qty: 0, rate: 10},
{name: 'x', qty: 10, rate: 2},
{name: 'y', qty: 5, rate: 20},
{name: 'y', qty: 55, rate: 11}]
const obj = data.reduce((a, { name, ...rest }) => {
if (!a[name]) a[name] = { name, pricing: [] };
a[name].pricing.push(rest);
return a;
}, {});
const output = Object.values(obj);
console.log(output);
You can do that using reduce()
var data = [
{name: 'x', qty: 0, rate: 10},
{name: 'x', qty: 10, rate: 2},
{name: 'y', qty: 5, rate: 20},
{name: 'y', qty: 55, rate: 11}]
let res = data.reduce((ac,a) => {
let i = ac.findIndex(x => x.name === a.name);
if(i === -1) i = ac.push({name:a.name,pricing:[]}) - 1
ac[i].pricing.push({qty:a.qty,rate:a.rate});
return ac;
},[])
console.log(res);
Your code is actually fine, except for a small mistake. You start a chain with data, and then you try to groupBy the data. Since non of the items return true for this predicate, all are bundled under a single group, and this is the reason for your single object.
You need to change .groupBy(data, 'name') to .groupBy('name').
Example:
var data = [{ name: 'x', qty: 0, rate: 10 }, { name: 'x', qty: 10, rate: 2 }, { name: 'y', qty: 5, rate: 20 }, { name: 'y', qty: 55, rate: 11 }];
var m = _.chain(data)
.groupBy('name') // group by name, and not by data, 'name'
.map(function(i) {
return {
name: _.first(i).name,
pricing: _.map(i, function(r) {
return _.pick(r, ['qty', 'rate'])
})
}
})
console.log(m);
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

algorithm to add up objects in an array without mutating the original array

I have an array of pending payments as objects and I want to know the total of all payments together as they are for the same shops. when the function is called once it calculates correctly, when I call it again it mutates the original array of objects.
I do not understand why it is mutating it when I am mapping over it.
I need the function to not mutate the original array of objects. It should do the calculation and just give me the result. Neither should it add on the current sum if it is called again. It should do it from scratch.
let pending = [
{Date: "20/12/2018",
Company:[
{Name: "Asda", Amount: 5.5},
{Name: "M&S", Amount: 10},
{Name: "Nisa", Amount: 15},
{Name: "Iceland", Amount: 10},
{Name: "Tesco", Amount: 5}
]},
{Date: "20/12/2018",
Company:[
{Name: "Asda", Amount: 5.5},
{Name: "M&S", Amount: 10},
{Name: "Nisa", Amount: 15},
{Name: "Iceland", Amount: 10},
{Name: "Tesco", Amount: 5}
]},
{Date: "20/12/2018",
Company:[
{Name: "Asda", Amount: 5.5},
{Name: "M&S", Amount: 10},
{Name: "Nisa", Amount: 15},
{Name: "Iceland", Amount: 10},
{Name: "Tesco", Amount: 5}
]},
{Date: "20/12/2018",
Company:[
{Name: "Asda", Amount: 5.5},
{Name: "M&S", Amount: 10},
{Name: "Nisa", Amount: 15},
{Name: "Iceland", Amount: 10},
{Name: "Tesco", Amount: 5}
]}
]
function returnSpendTotals() {
let sumSpend = []
let spendArray = pending.map(activities => activities.Company)
spendArray.flat().forEach(spend => {
let shopName = sumSpend.find(item => item.Name === spend.Name)
if (shopName) {
shopName.Amount += spend.Amount
} else {
sumSpend.push(spend)
}
})
return sumSpend
}
it should return each time I call returnSpendTotals()
[{Name: "Asda", Amount: 22},
{Name: "M&S", Amount: 40},
{Name: "Nisa", Amount: 60},
{Name: "Iceland", Amount: 40},
{Name: "Tesco", Amount: 20}]
But if I call it a second time this is what I get
[{Name: "Asda", Amount: 38.5},
{Name: "M&S", Amount: 70},
{Name: "Nisa", Amount: 105},
{Name: "Iceland", Amount: 70},
{Name: "Tesco", Amount: 35}]
and pending first object is now
{Company: [
{Name: "Asda", Amount: 38.5},
{Name: "M&S", Amount: 70},
{Name: "Nisa", Amount: 105},
{Name: "Iceland", Amount: 70},
{Name: "Tesco", Amount: 35}],
Date: "20/12/2018"}
And the rest of the objects in pending are unchanged
You could take the destructured properties and build a new object for the result set, to prevent a same object reference to the used data.
function returnSpendTotals() {
return pending.reduce((r, { Company }) => {
Company.forEach(({ Name, Amount }) => {
let shop = r.find(item => item.Name === Name)
if (shop) {
shop.Amount += Amount;
} else {
r.push({ Name, Amount });
}
});
return r;
}, []);
}
let pending = [{ Date: "20/12/2018", Company: [{ Name: "Asda", Amount: 5.5 }, { Name: "M&S", Amount: 10 }, { Name: "Nisa", Amount: 15 }, { Name: "Iceland", Amount: 10 }, { Name: "Tesco", Amount: 5 }] }, { Date: "20/12/2018", Company: [{ Name: "Asda", Amount: 5.5 }, { Name: "M&S", Amount: 10 }, { Name: "Nisa", Amount: 15 }, { Name: "Iceland", Amount: 10 }, { Name: "Tesco", Amount: 5 }] }, { Date: "20/12/2018", Company: [{ Name: "Asda", Amount: 5.5 }, { Name: "M&S", Amount: 10 }, { Name: "Nisa", Amount: 15 }, { Name: "Iceland", Amount: 10 }, { Name: "Tesco", Amount: 5 }] }, { Date: "20/12/2018", Company: [{ Name: "Asda", Amount: 5.5 }, { Name: "M&S", Amount: 10 }, { Name: "Nisa", Amount: 15 }, { Name: "Iceland", Amount: 10 }, { Name: "Tesco", Amount: 5 }] }];
console.log(returnSpendTotals());
When you find a shop:
let shopName = sumSpend.find(item => item.Name === spend.Name)
you obtain a reference to an object that's part of your data structure. Your code then modifies that object:
shopName.Amount += spend.Amount
I'm not sure exactly what to suggest as a fix because it's not completely clear what you're trying to do. Probably you should be keeping a separate running total instead of altering your "shop" objects.
Also note that the .map() process earlier in your function:
let spendArray = pending.map(activities => activities.Company)
similarly results in a list that's made up of references back into the original data structure.
With this solution, it's just simple, it works, nothing fancy going on, just create an object, assign properties to that object, and iterate over the data object, that's it.
const data=[{Date:"20/12/2018",Company:[{Name:"Asda",Amount:5.5},{Name:"M&S",Amount:10},{Name:"Nisa",Amount:15},{Name:"Iceland",Amount:10},{Name:"Tesco",Amount:5}]},{Date:"20/12/2018",Company:[{Name:"Asda",Amount:5.5},{Name:"M&S",Amount:10},{Name:"Nisa",Amount:15},{Name:"Iceland",Amount:10},{Name:"Tesco",Amount:5}]},{Date:"20/12/2018",Company:[{Name:"Asda",Amount:5.5},{Name:"M&S",Amount:10},{Name:"Nisa",Amount:15},{Name:"Iceland",Amount:10},{Name:"Tesco",Amount:5}]},{Date:"20/12/2018",Company:[{Name:"Asda",Amount:5.5},{Name:"M&S",Amount:10},{Name:"Nisa",Amount:15},{Name:"Iceland",Amount:10},{Name:"Tesco",Amount:5}]}];
const companies = {};
data.forEach(obj => obj.Company.forEach(o => {
companies[o.Name] = companies[o.Name] == null ? 0 : companies[o.Name];
companies[o.Name] += o.Amount;
}));
console.log(companies);
Edit
This one is pretty similar, only slightly more fancy... This is inspired by the answer from Nina Scholz, I am a fan of the syntax.
const pending = [{ Date: "20/12/2018", Company: [{ Name: "Asda", Amount: 5.5 }, { Name: "M&S", Amount: 10 }, { Name: "Nisa", Amount: 15 }, { Name: "Iceland", Amount: 10 }, { Name: "Tesco", Amount: 5 }] }, { Date: "20/12/2018", Company: [{ Name: "Asda", Amount: 5.5 }, { Name: "M&S", Amount: 10 }, { Name: "Nisa", Amount: 15 }, { Name: "Iceland", Amount: 10 }, { Name: "Tesco", Amount: 5 }] }, { Date: "20/12/2018", Company: [{ Name: "Asda", Amount: 5.5 }, { Name: "M&S", Amount: 10 }, { Name: "Nisa", Amount: 15 }, { Name: "Iceland", Amount: 10 }, { Name: "Tesco", Amount: 5 }] }, { Date: "20/12/2018", Company: [{ Name: "Asda", Amount: 5.5 }, { Name: "M&S", Amount: 10 }, { Name: "Nisa", Amount: 15 }, { Name: "Iceland", Amount: 10 }, { Name: "Tesco", Amount: 5 }] }];
const compelte = pending.reduce((r, { Company }) => {
Company.forEach(({ Name, Amount }) => r[Name] == null ? r[Name] = 0 : r[Name] += Amount);
return r;
}, {});
console.log(compelte);
function returnSpendTotals() {
let companies = {}
pending.forEach(item => {
item.Company.forEach(company => {
if (!companies[company.Name]) {
companies[company.Name] = company.Amount;
} else {
companies[company.Name] += company.Amount;
}
})
})
return companies
}
returnSpendTotals(pending)
// result: {Asda: 22, M&S: 40, Nisa: 60, Iceland: 40, Tesco: 20}

Javascript loop an object array and return a new array

To use react, I have an object array like this:
{
_id: 1,
items: [
{ goodName: "cake", amount: 10 },
{ goodName: "potato", amount: 11 },
{ goodName: "apple", amount: 15 }
]
}
{
_id: 2,
items: [
{ goodName: "cake", amount: 10 },
{ goodName: "potato", amount: 11 },
{ goodName: "apple", amount: 15 }
]
}
{
_id: 3,
items: [
{ goodName: "cake", amount: 10 },
{ goodName: "potato", amount: 11 },
{ goodName: "apple", amount: 15 }
]
}
Now, I want to loop through this object array,and return an array
containing the amount's accumulated value of each good.I want to use .map() methods to make it like this:
var value = items.map(function(item) {
var amounts = 0;
var amount=[];
for (var i=0; i<=myArr.length; i++) {
if (myArr[i] === item.name) {
amounts=amounts+item.amount;
amount.push(amounts);
}
}
})
But it doesn't work. myArr is an array I use the new Set() and
Array.from() method to loop through the goodName and return it. I don't know what method I use can make it, is everyone has another way?
I have written code to loop over your information and return tallies of the total amounts of each good type. However, several clarifications are required.
The information in your question needs to be wrapped in square brackets, as the outer objects you show need to be elements in an array.
I am returning an object, not an array as you suggest in your question. That allows the results to contain information about which items each tally corresponds to, i.e. {good1: total1, good2: total2, ...}
I include an extra (fourth) object just to show that the code requires neither the same number of goods nor even the same identities of goods in each array element.
var arr = [
{_id: 1, items: [
{goodName: "cake", amount: 10},
{goodName: "potato", amount: 11},
{goodName: "apple", amount: 15}
]},
{_id: 2, items: [
{goodName: "cake", amount: 10},
{goodName: "potato", amount: 11},
{goodName: "apple", amount: 15}
]},
{_id: 3, items: [
{goodName: "cake", amount: 10},
{goodName: "potato", amount: 11},
{goodName: "apple", amount: 15}
]},
{_id: 4, items: [
{goodName: "potato", amount: 1000},
{goodName: "peach", amount: 2000}
]}
];
var results = {};
arr.forEach(arrElmt => {
arrElmt.items.forEach(item => {
results[item.goodName] = (results[item.goodName] || 0) + item.amount;
});
});
var res = JSON.stringify(results);
console.log(res);
You can't use only map, because you are accumulating the values of the items. I would use reduce:
const arr = [
{_id: 1, items: [
{goodName: "cake", amount: 10},
{goodName: "potato", amount: 11},
{goodName: "apple", amount: 15}
]},
{_id: 2, items: [
{goodName: "cake", amount: 10},
{goodName: "potato", amount: 11},
{goodName: "apple", amount: 15}
]},
{_id: 3, items: [
{goodName: "cake", amount: 10},
{goodName: "potato", amount: 11},
{goodName: "apple", amount: 15}
]},
{_id: 4, items: [
{goodName: "potato", amount: 1000},
{goodName: "peach", amount: 2000}
]}
];
let results = [].concat.apply([], arr.map(elem => elem.items))
.reduce((results, item) => {
results[item.goodName] = (results[item.goodName] || 0) + item.amount;
return results;
}, {});
document.write(JSON.stringify(results));
JS does not have flatMap, so the [].concat.apply dance is a little weird, but any good library will have it.

Categories

Resources