There is an array of products, each product has structure like this:
{
id: 1,
name: "product 1",
materials: [
{
id: 1,
name: "material 1"
},
{
id: 2,
name: "material 2"
},
{
id: 3,
name: "material 3"
}
]
}
Each product has an array with different quantity of materials.
Also there is an array of material IDs, for example [1, 4, 7, 2, 5].
How can I filter the array of products to leave only products, where materials has IDs which are in the array of materials IDs?
try
products.filter(p=> p.materials.some(m=> materialsIds.includes(m.id)));
let materialsIds = [1, 4, 7, 2, 5];
let products = [
{ id: 1, name: "product 1", materials: [{id: 1,name: "material 1"},{id: 2,name: "material 2"},{id: 3, name: "material 3"}]},
{ id: 2, name: "product 2", materials: [{id: 2, name: "material 2"}]},
{ id: 3, name: "product 3", materials: [{id: 3, name: "material 3"}]},
]
let r = products.filter(p=> p.materials.some(m=> materialsIds.includes(m.id)));
console.log('Filtered products ids', r.map(p=>p.id));
console.log('Filtered products', JSON.stringify(r));
You can do this :
import {intersection} from 'lodash'
const products = [...]
const materialIds = [1,4,7,2,5]
// some function use es5+
const targetProducts = products.filter(p => intersection(p.materials.map(m => m.id), materialIds).length)
// use lodash only import {filter, map, intersection} from 'lodash'
const targetProducts = filter(products, p => intersection(map(p.materials, 'id'), materialIds).length)
You can do that using filter() some()and includes()
Use filter() on the main array of products
Then use some() on the materials of object.
Check if mats(material ids) includes id of material
let arr = [{ id: 1, name: "product 1", materials: [ { id: 1, name: "material 1" }, { id: 2, name: "material 2" }, { id: 3, name: "material 3" } ] },{ id: 2, name: "product 2", materials: [ { id: 11, name: "material 11" }, { id: 22, name: "material 22" }, { id: 33, name: "material 33" } ] }
]
let mats = [1,5,6];
let res = arr.filter(x => x.materials.some(z=> mats.includes(z.id)));
console.log(res)
const products = [
{
id: 1,
name: 'product 1',
materials: [
{
id: 1,
name: 'material 1'
},
{
id: 7,
name: 'material 7'
},
{
id: 5,
name: 'material 5'
}
]
},
{
id: 2,
name: 'product 2',
materials: [
{
id: 1,
name: 'material 1'
},
{
id: 2,
name: 'material 2'
},
{
id: 3,
name: 'material 3'
}
]
}
];
const materials = [3, 4];
console.log(
products.filter(product => {
for (let i = 0; i < product.materials.length; i++) {
if (materials.includes(product.materials[i].id)) return true;
}
})
);
I would do it like this:
products.filter(product => {
for (let i = 0; i < product.materials.length; i++) {
if (materials.includes(product.materials[i].id)) return true;
}
})
Related
How can I get the result from arr1 and arr2, When the ID matches I need to copy the content from arr1
const arr1 = [
{ id: 1, name: "omar" },
{ id: 2, name: "laith" },
{ id: 3, name: "aref" },
]
const arr2 = [
{ id: 1, rating: "good" },
{ id: 2, rating: "very good" },
{ id: 2, rating: "very good" },
{ id: 3, rating: "Excellence" },
{ id: 3, rating: "Excellence" },
]
//expected output
const result = [
{ id: 1, rating: "good", name: "omar" },
{ id: 1, rating: "good", name: "omar" },
{ id: 2, rating: "very good", name: "laith" },
{ id: 3, rating: "Excellence", name: "aref" },
{ id: 3, rating: "Excellence", name: "aref" },
]
use reduce with filter
const arr1 = [ { id: 1, name: "omar" }, { id: 2, name: "laith" }, { id: 3, name: "aref" }, ];
const arr2 = [ { id: 1, rating: "good" }, { id: 2, rating: "very good" }, { id: 2, rating: "very good" }, { id: 3, rating: "Excellence" }, { id: 3, rating: "Excellence" }, ];
const result = arr1.reduce((acc,item) => {
const list = arr2.filter(i => i.id === item.id)
return [...acc, ...list.map(i => ({id: i.id,rating:i.rating, name: item.name}))]
}, [])
console.log(result)
Basically with a loop. Actually 2. Using a temporary object (result) as dictionary (or map) we can make it efficient searching for a match to each id. This is of complexity O(n) basically.
const arr1 = [ { id: 1, name: "omar" }, { id: 2, name: "laith" }, { id: 3, name: "aref" }, ];
const arr2 = [ { id: 1, rating: "good" }, { id: 2, rating: "very good" }, { id: 2, rating: "very good" }, { id: 3, rating: "Excellence" }, { id: 3, rating: "Excellence" }, ];
var result = {}
arr1.forEach(function(item1) {
result[item1.id] = item1;
});
arr2.forEach(function(item2) {
result[item2.id] = (result[item2.id] || item2)
result[item2.id]['rating'] = item2.rating
})
result = Object.values(result)
console.log(result)
I have an array of objects that I have to process and then include data from it to HTML. The problem is that now everything is displayed one by one and if I try to toggle class to li element, it toggles to all li elements. The data can be changed dynamically so I cannot access elements by ID.
I want to access the "main" category first (desserts, water, tea), then be able to proceed to subcategory of the selected main category etc. Further I will create a menu like in the screenshot (a one menu, a pic shows different states of it)
I have 2 problems now:
For some reason the main category isn't showing at all - why is it happening?
How can I access the elements according to hierarchy and nesting?
const menu = [
{
id: 1,
name: "Desserts",
groups: [
{
id: 2,
name: "Cold",
groups: [
{
id: 3,
name: "Ice Cream",
groups: []
},
{
id: 4,
name: "Cold brew coffee",
groups: []
}
]
},
{
id: 5,
name: "Hot",
groups: [
{
id: 6,
name: "Pancakes",
groups: []
},
{
id: 7,
name: "Apple pie",
groups: []
}
]
}
]
},
{
id: 8,
name: "Water",
groups: []
},
{
id: 7,
name: "Tea",
groups: [
{
id: 8,
name: "Green tea",
groups: [
{
id: 9,
name: "With Jasmine",
groups: []
},
{
id: 10,
name: "Plain",
groups: []
}
]
},
{
id: 11,
name: "Black Tea",
groups: []
}
]
}
];
let menuEl = document.querySelector(".funding__categories");
addElements(menuEl, menu[0].groups);
function addElements(parent, arr) {
let allCategories = parent.appendChild(document.createElement("ul"));
allCategories.classList.add("parent");
arr.forEach((el) => {
let subCategory = allCategories.appendChild(document.createElement("li"));
subCategory.dataset.id = el.id;
subCategory.textContent = el.name;
if (el.groups.length > 0) addElements(subCategory, el.groups);
});
}
<div class="funding__categories"></div>
The first problem is because you're passing menu[0].groups to the function. That skips over the top-level categories and starts at the items nested under Desserts. Pass menu as the argument.
I don't understand the second question. Access them in what way?
const menu = [
{
id: 1,
name: "Desserts",
groups: [
{
id: 2,
name: "Cold",
groups: [
{
id: 3,
name: "Ice Cream",
groups: []
},
{
id: 4,
name: "Cold brew coffee",
groups: []
}
]
},
{
id: 5,
name: "Hot",
groups: [
{
id: 6,
name: "Pancakes",
groups: []
},
{
id: 7,
name: "Apple pie",
groups: []
}
]
}
]
},
{
id: 8,
name: "Water",
groups: []
},
{
id: 7,
name: "Tea",
groups: [
{
id: 8,
name: "Green tea",
groups: [
{
id: 9,
name: "With Jasmine",
groups: []
},
{
id: 10,
name: "Plain",
groups: []
}
]
},
{
id: 11,
name: "Black Tea",
groups: []
}
]
}
];
let menuEl = document.querySelector(".funding__categories");
addElements(menuEl, menu);
function addElements(parent, arr) {
let allCategories = parent.appendChild(document.createElement("ul"));
allCategories.classList.add("parent");
arr.forEach((el) => {
let subCategory = allCategories.appendChild(document.createElement("li"));
subCategory.dataset.id = el.id;
subCategory.textContent = el.name;
if (el.groups.length > 0) addElements(subCategory, el.groups);
});
}
<div class="funding__categories"></div>
How do I flatten the nested Array in the Array?
Here is the example input Array,
const input = [
{
id: 1,
name: 'Charles',
otherFields: [{
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}]
}, {
id: 4,
name: 'Charles',
otherFields: [{
id: 5,
name: 'Pung',
}, {
id: 6,
name: 'James',
}]
}
]
Output Array I want to get.
[{
id: 1,
name: 'Charles'
}, {
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}, {
id: 4,
name: 'Charles'
}, {
id: 5,
name: 'Pung',
}, {
id: 6,
name: 'James',
}]
I want to somehow get the output in one statement like
input.map((sth) => ({...sth??, sth.field...})); // I'm not sure :(
With flatMap you can take out the otherFields property, and returning an array containing the parent item and the other array:
const input = [{
id: 1,
name: 'Charles',
otherFields: [{
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}]
}];
console.log(
input.flatMap(({ otherFields, ...item }) => [item, ...otherFields])
);
For more than one level, you could take a recursive approach of flattening.
const
flat = ({ otherFields = [], ...o }) => [o, ...otherFields.flatMap(flat)],
input = [{ id: 1, name: 'Charles', otherFields: [{ id: 2, name: 'Pung' }, { id: 3, name: 'James', otherFields: [{ id: 4, name: 'Jane' }] }] }],
result = input.flatMap(flat);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have static array constant of objects something similar to below.
export const EMPLOYEES = [
{
id: 2,
name: ‘John’,
},
{
id: 3,
name: ‘Doe’,
},
{
id: 4,
name: ‘Bull’,
},
{
id: 5,
name: ‘Scott’,
},
];
Now I need to add the last element only based on if some condition is true. Some this like if isAmerican() is true.
Can somebody help me here how to add element based on the condition? Thanks.
You can do it using spread operator:
export const EMPLOYEES = [
{
id: 2,
name: "John",
},
{
id: 3,
name: "Doe",
},
{
id: 4,
name: "Bull",
},
{
id: 5,
name: "Scott",
},
... isAmerican() ? [{ id: 6, name: "Jemmy"}] : []
];
You should never modify (or try to modify) a constant. I can see two ways you can do this:
Create a pure function to return a new constant with the new object added to the array
Use a spread operator in the definition of the constant
Option 1: Pure function
function makeNewArray(array, objectToAppend, isAmerican) {
return isAmerican ? [...array, objectToAppend] : array
}
const EMPLOYEES = [
{
id: 2,
name: "John",
},
{
id: 3,
name: "Doe",
},
{
id: 4,
name: "Bull",
},
{
id: 5,
name: "Scott",
}
];
const arrayWithAmerican = makeNewArray(EMPLOYEES, { id: 6, name: "American Frank"}, true);
const arrayWithoutAmerican = makeNewArray(EMPLOYEES, { id: 6, name: "Not American Frank"}, false);
console.log(arrayWithAmerican);
console.log(arrayWithoutAmerican);
Option 2: Spread operator
function isAmerican(){
// generic code here.
return true;
}
const EMPLOYEES = [
{
id: 2,
name: "John",
},
{
id: 3,
name: "Doe",
},
{
id: 4,
name: "Bull",
},
{
id: 5,
name: "Scott",
},
... isAmerican() ? [{ id: 6, name: "American Frank"}] : []
];
If the condition will be fulfilled, simply push an object to your EMPLOYEES array:
let isAmerican = true;
const EMPLOYEES = [
{
id: 2,
name: "John",
},
{
id: 3,
name: "Doe",
},
{
id: 4,
name: "Bull",
},
{
id: 5,
name: "Scott",
},
];
if(isAmerican) {
EMPLOYEES.push({
id: 6,
name: "Frank"
})
}
console.log(EMPLOYEES)
Fiddle: https://jsfiddle.net/rqx35pLz/
I have an array of objects with an unlimited number of nested children objects like this:
var items = [
{
id: 1,
name: 'Item 1',
children: [
{
id: 2,
name: 'Item 2',
children: [],
}
]
},
{
id: 2,
name: 'Item 2',
children: [],
},
{
id: 3,
name: 'Item 3',
children: [
{
id: 1,
name: 'Item 1',
children: [
id: 2,
name: 'Item 2',
children: [],
]
}
]
}
];
I want to update every occurrence of object with id 2 to have a name of "This is a cool object".
I'm not sure if this needs recursion or if some type of find and replace will do.
var newObject = {
id: 2,
name: 'This is a cool object',
children: []
}
I want to replace every occurrence of any object with id 2 with the new object (regardless of the rest of the objects contents).
I tried looping through but then realized that it could potentially be unlimited levels deep.
With recursion.
var items = [ { "id": 1, "name": "Item 1", "children": [ { "id": 2, "name": "Item 2", "children": [] } ] }, { "id": 2, "name": "Item 2", "children": [] }, { "id": 3, "name": "Item 3", "children": [ { "id": 1, "name": "Item 1", "children": [{ "id": 2, "name": "Item 2", "children": [] }] } ] }];
function loop(array, targetId) {
array.forEach((e) => {
if(e.id === targetId) {
e.name = 'This is a cool object';
}
if (e.children && e.children.length > 0) {
loop(e.children, targetId);
}
});
}
loop(items, 2);
console.log(items);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try this single line of code with Array filter() method.
function findID(items) {
return items.filter(obj => (obj.id === 2)?obj.name='This is a cool object':findID(obj.children));
}
var res = findID(items);
Working Demo
var items = [
{
id: 1,
name: 'Item 1',
children: [
{
id: 2,
name: 'Item 2',
children: [],
}
]
},
{
id: 2,
name: 'Item 2',
children: [],
},
{
id: 3,
name: 'Item 3',
children: [
{
id: 1,
name: 'Item 1',
children: [
{
id: 2,
name: 'Item 2',
children: [],
}
]
}
]
}
];
function findID(items) {
return items.filter(obj => (obj.id === 2)?obj.name='This is a cool object':findID(obj.children));
}
console.log(findID(items));