fillter arrays of objects - javascript

i have two arrays.
const department = [
{ id: '1', name: 'department1' },
{ id: '2', name: 'department2' },
];
const models = [
{
id: '23',
name: 'model1',
departments: [{ id: '1', name: 'department1' }],
},
{
id: '54',
name: 'model2',
departments: [
{ id: '1', name: 'department1' },
{ id: '2', name: 'department2' },
],
},
];
i need to render accordions with department names and accordion details with matching models names. My question is how to filter those arrays to get models

We can map through the departments array, and add a models property that equals the models array, but filtered only to the ones that contain a matching department id.
const departments = [
{ id: "1", name: "department1" },
{ id: "2", name: "department2" },
];
const models = [
{
id: "23",
name: "model1",
departments: [{ id: "1", name: "department1" }],
},
{
id: "54",
name: "model2",
departments: [
{ id: "1", name: "department1" },
{ id: "2", name: "department2" },
],
},
];
const getDepartmentsWithModels = () => {
return departments.map((department) => {
return {
...department,
models: models.filter((model) => {
const modelDepartmentIds = model.departments.map(({ id }) => id);
return modelDepartmentIds.includes(department.id);
}),
};
});
};
console.log(getDepartmentsWithModels());
// [ { id: '1', name: 'department1', models: [ [Object], [Object] ] },
// { id: '2', name: 'department2', models: [ [Object] ] } ]```

I've built some code, which iterates over the departments. For each department it iterates the models and for each model it checks if the department is within the model departments.
const department =
[
{ id: '1', name: 'department1' },
{ id: '2', name: 'department2' }
]
const models =
[
{
id: '23',
name: 'model1',
departments: [{ id: '1', name: 'department1' }]
},
{
id: '54',
name: 'model2',
departments: [{ id: '1', name: 'department1' },{ id: '2', name: 'department2' }]
}
]
department.forEach( dep => {
console.log(`Department: ${dep.name}`)
models.forEach(model => {
if (model.departments.find(modelDep => dep.id===modelDep.id)) {
console.log(` Model: ${model.name}`)
}
})
})
If you could change your data objects, then your code could be much smoother.
I've changed your data objects slightly by just reducing the departments in a model to be an array of department id's. This code iterates over the departments. For each department it filters the models and iterates over the filtered models to output them to the console. This is lesser code and provides much better performance.
const department =
[
{ id: '1', name: 'department1' },
{ id: '2', name: 'department2' }
]
const models =
[
{
id: '23',
name: 'model1',
departments: ['1']
},
{
id: '54',
name: 'model2',
departments: ['1', '2']
}
]
department.forEach( dep => {
console.log(`Department: ${dep.name}`)
models.filter(model => model.departments.includes(dep.id)).forEach(model => {
console.log(` Model: ${model.name}`)
})
})

There are two solutions.
Using Array.reduce() --> returns an object where the key is department name and value is an array of the names of matching models:
let data1 = models.reduce((res, curr) => {
curr.departments.forEach(dep => {
if (!res[dep.name]) {
res[dep.name] = [curr.name]
} else {
if (!res[dep.name].includes(curr.name)) {
res[dep.name].push(curr.name);
}
}
})
return res;
}, {});
Using map and filter --> returns an array of kind:
[{department: [names of the models]},...]
let data2 = department.map(dep => {
let matchingModels = models.filter(model => {
return model.departments.filter(modDep => {
return modDep.name === dep.name;
}).length > 0;
}).map(mod => {
return mod.name;
});
return {
department: dep.name,
models: matchingModels
}
});

Related

Mapping array in javacript app in a react app

This is my array, I'm working on react app
const categoryObj = [
{
id: "463e989a-c4f2-4616-85c5-0cb610c5fff0",
name: "Women",
subCategory: [
{
id: "91ba7308-b68e-4d0c-85d8-0cc8272c6bc8",
name: "All",
icon: "AllIcon"
},
{
id: "0e0712c5-0b5a-4d4e-acf5-3d7faf2caa2a",
name: "Clothes",
icon: "ClothesIcon",
sections: [
{
id: "9b7a7a58-04a1-4aba-ba68-0e6b1390021e",
name: "All",
href: "Women/Clothes/All".split(' ').join('-').trim().toLowerCase()
}
]
}
]
}
]
how can I access "women" in this array ? (I have many items like "women" this is just a sample of a large array. if you can suggest a mapping method it's better.)
You can map through it to get the name value in this way:
categoryObj.map((category) => category.name)
const categoryObj = [
{
id: "463e989a-c4f2-4616-85c5-0cb610c5fff0",
name: "Women",
subCategory: [
{
id: "91ba7308-b68e-4d0c-85d8-0cc8272c6bc8",
name: "All",
icon: "AllIcon"
},
{
id: "0e0712c5-0b5a-4d4e-acf5-3d7faf2caa2a",
name: "Clothes",
icon: "ClothesIcon",
sections: [
{
id: "9b7a7a58-04a1-4aba-ba68-0e6b1390021e",
name: "All",
href: "Women/Clothes/All".split(' ').join('-').trim().toLowerCase()
}
]
}
]
},
{
id: "463e989a-c4f2-4616-85c5-0cb610c5fff0",
name: "Men",
subCategory: [
{
id: "91ba7308-b68e-4d0c-85d8-0cc8272c6bc8",
name: "All",
icon: "AllIcon"
},
{
id: "0e0712c5-0b5a-4d4e-acf5-3d7faf2caa2a",
name: "Clothes",
icon: "ClothesIcon",
sections: [
{
id: "9b7a7a58-04a1-4aba-ba68-0e6b1390021e",
name: "All",
href: "Women/Clothes/All".split(' ').join('-').trim().toLowerCase()
}
]
}
]
},
{
id: "463e989a-c4f2-4616-85c5-0cb610c5fff0",
name: "Children",
subCategory: [
{
id: "91ba7308-b68e-4d0c-85d8-0cc8272c6bc8",
name: "All",
icon: "AllIcon"
},
{
id: "0e0712c5-0b5a-4d4e-acf5-3d7faf2caa2a",
name: "Clothes",
icon: "ClothesIcon",
sections: [
{
id: "9b7a7a58-04a1-4aba-ba68-0e6b1390021e",
name: "All",
href: "Women/Clothes/All".split(' ').join('-').trim().toLowerCase()
}
]
}
]
}
]
const result = categoryObj.filter(obj => obj.name === 'Women')
console.log('multi objects :', result)
// if unique with name
const resultUnique = categoryObj.find(obj => obj.name === 'Women')
console.log('unique object :', resultUnique)
This object contains an object and have another variations as sub. If you want to access first name,
categoryObj.map((it) => {
//You can handle it like this
console.log(it.name)
})
But if you want all name of all subCategory,
categoryObj[0].subCategory.map((cat) => {
//You can handle it like this
console.log(cat.name)
})
You have same object-type in and out.
const res = categoryObj.filter(item=>item.name === 'Women');

Grouping a object value inside n level nested array

I have an array like this. How to group all child Ids into an array?
My solution below is not giving me all child elements. Where is the mistake? and suggest me any other ways
const data = {
name: '1',
id: '05f770d5',
child: [
{
name: '2',
id: '0ecfc8e1',
child: [
{
name: '3',
id: '2e1eb75c',
child: [],
},
],
},
{
name: '1c',
id: 'b9ee9864',
child: [
{
name: '8',
id: '575f4760',
child: [],
},
],
},
],
};
let array1 = [];
function sumChild(data) {
data.child.forEach((data) => {
array1.push(data.id);
sumChild(data?.child[0]);
});
return array1;
}
sumChild(data);
console.log(array1);
function sumChild(data) {
data.child?.forEach((data) => {
array1.push(data.id);
sumChild(data);
});
return array1;
}

combining similar key/value pair into an array

I am wondering if I can combine multiple objects based on a given id into an array of an object? Hopefully I can explain this better below:
trying to have an output of each index item of carCollection to be like this:
[
{
brand: 'Porsche',
model: ['Cayenne', 'Macan'],
id: 1
},
{
brand: 'BMW',
model: ['M4','M3'],
id: 3
}
]
But the code below duplicates id:1 car brand Porsche into the carCollection:
[
{
brand: 'Porsche',
model: ['Cayenne'],
id: 1,
},
{
brand: 'Porsche',
model: ['Macan'],
id: 1
}
]
let cars = {
brands: [ {name:'Porsche', id:1}, {name:'Mercedes-Benz', id:2},{name:'BMW', id:3},],
models: [ {name:'Cayenne', id:1}, {name:'C45', id:2}, {name:'M4', id:3}, {name:'M3', id:3}, {name:'Macan', id:1}]
}
// empty array
let carCollection = []
let { brands, models } = cars;
function carMatcher(brands, models){
for(let brand of brands){
for(let model of models){
const carObject = {
brand: '',
model: [],
id: 0
}
if(model.id === brand.id){
carObject.brand = brand.name
carObject.model.push(model.name)
carObject.id = brand.id
carCollection.push(carObject)
}
}
}
}
carMatcher(brands, models)
You can easily achieve this result using Map and forEach
let cars = {
brands: [
{ name: "Porsche", id: 1 },
{ name: "Mercedes-Benz", id: 2 },
{ name: "BMW", id: 3 },
],
models: [
{ name: "Cayenne", id: 1 },
{ name: "C45", id: 2 },
{ name: "M4", id: 3 },
{ name: "M3", id: 3 },
{ name: "Macan", id: 1 },
],
};
const dict = new Map();
cars.brands.forEach(({ name, id }) => {
dict.set(id, { brand: name, id, model: [] });
});
cars.models.forEach(({ name, id }) => {
if (dict.has(id)) dict.get(id).model.push(name);
});
const result = [...dict.values()];
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
EDIT: Simpler version
let cars = {
brands: [
{ name: "Porsche", id: 1 },
{ name: "Mercedes-Benz", id: 2 },
{ name: "BMW", id: 3 },
],
models: [
{ name: "Cayenne", id: 1 },
{ name: "C45", id: 2 },
{ name: "M4", id: 3 },
{ name: "M3", id: 3 },
{ name: "Macan", id: 1 },
],
};
let dict = {},
result = [];
for (let val of cars.brands) {
dict[val.id] = {
brand: val.name,
id: val.id,
model: [],
};
}
for (let val of cars.models) {
const id = val.id;
const name = val.name;
const objInDict = dict[id];
if (objInDict) {
objInDict.model.push(name);
}
}
for (let key in dict) {
result.push(dict[key]);
}
console.log(result);
Simplest
let cars = {
brands: [
{ name: "Porsche", id: 1 },
{ name: "Mercedes-Benz", id: 2 },
{ name: "BMW", id: 3 },
],
models: [
{ name: "Cayenne", id: 1 },
{ name: "C45", id: 2 },
{ name: "M4", id: 3 },
{ name: "M3", id: 3 },
{ name: "Macan", id: 1 },
],
};
let result = [];
const { brands, models } = cars;
for (let brand of brands) {
const { name, id } = brand;
const newObj = { brand: name, id, model: [] };
for (let model of models) {
const { name, id } = model;
if (newObj.id === id) {
newObj.model.push(name);
}
}
result.push(newObj);
}
console.log(result);

Filter Array of Objects with a Object reside in Nested Array property

I have the following use-case,
I have,
An array of objects that contains a list of courses
An array of objects that contains students with a nested array: studies
I need to find a courses which are not studied by any student.
How to achieve that?
follow is the code sinnpient.
let courses = [
{ id: 'A' },
{ id: 'B' },
{ id: 'C' },
{ id: 'D' }, <-- not studied by any one
{ id: 'E' },
{ id: 'F' }, <-- not studied by any one
];
let students = [
{
name: 'STD1',
study: [
{ id: 'A' },
{ id: 'C' }
]
},
{
name: 'STD2',
study: [
{ id: 'B' },
{ id: 'E' }
]
}
];
expected output
const notUsedCourse = [{ id: 'D' }, { id: 'F' }];
You can save course ids which have been studied by students into a Set so that we can check if a course has been studied later.
The advantage over the solution with filter and some combination is that this solution will be much faster when the size of courses and students gets bigger since the former has the time complexity of O(n^3) .
const courses = [
{ id: 'A' },
{ id: 'B' },
{ id: 'C' },
{ id: 'D' },
{ id: 'E' },
{ id: 'F' },
];
const students = [
{
name: 'STD1',
study: [
{ id: 'A' },
{ id: 'C' }
]
},
{
name: 'STD2',
study: [
{ id: 'B' },
{ id: 'E' }
]
}
];
const usedCourseIds = new Set(students.flatMap(student => student.study).map(course => course.id));
const notUsedCourses = courses.filter(course => !usedCourseIds.has(course.id));
console.log(notUsedCourses);
You can use .filter with .some to loop through and search if a student has the course:
let courses = [
{ id: 'A' },
{ id: 'B' },
{ id: 'C' },
{ id: 'D' },
{ id: 'E' },
{ id: 'F' },
];
let students = [
{
name: 'STD1',
study: [
{ id: 'A' },
{ id: 'C' }
]
},
{
name: 'STD2',
study: [
{ id: 'B' },
{ id: 'E' }
]
}
];
let notUsedCourse = courses.filter(
course => !students.some(
student => student.study.some(
study => study.id === course.id
)
)
);
console.log(notUsedCourse);
You could get the visited courses first and then filter all courses.
var courses = [{ id: 'A' }, { id: 'B' }, { id: 'C' }, { id: 'D' }, { id: 'E' }, { id: 'F' }],
students = [{ name: 'STD1', study: [{ id: 'A' }, { id: 'C' }] }, { name: 'STD2', study: [{ id: 'B' }, { id: 'E' }] }],
seen = students.reduce(
(seen, { study }) => study.reduce((s, { id }) => s.add(id), seen),
new Set
),
missing = courses.filter(({ id }) => !seen.has(id));
console.log(missing)

Javascript filtering nested arrays

I'm trying to filter a on a nested array inside an array of objects in an Angular app. Here's a snippet of the component code -
var teams = [
{ name: 'Team1', members: [{ name: 'm1' }, { name: 'm2' }, { name: 'm3' }] },
{ name: 'Team2', members: [{ name: 'm4' }, { name: 'm5' }, { name: 'm6' }] },
{ name: 'Team3', members: [{ name: 'm7' }, { name: 'm8' }, { name: 'm9' }] }
];
What I'm trying to achieve is if I search for m5 for example my result should be -
var teams = [
{ name: 'Team1', members: [] },
{ name: 'Team2', members: [{ name: 'm5' }] },
{ name: 'Team3', members: [] }
];
So I've got teams and filteredTeams properties and in my search function I'm doing -
onSearchChange(event: any): void {
let value = event.target.value;
this.filteredTeams = this.teams.map(t => {
t.members = t.members.filter(d => d.name.toLowerCase().includes(value));
return t;
})
}
Now this does work to some extent however because I'm replacing the members it's destroying the array on each call (if that makes sense). I understand why this is happening but my question is what would be the best way to achieve this filter?
you were very close, the only thing that you did wrong was mutating the source objects in teams
basically you can use spread operator to generate a new entry and then return a whole new array with new values.
const teams = [
{ name: 'Team1', members: [{ name: 'm1' }, { name: 'm2' }, { name: 'm3' }] },
{ name: 'Team2', members: [{ name: 'm4' }, { name: 'm5' }, { name: 'm6' }] },
{ name: 'Team3', members: [{ name: 'm7' }, { name: 'm8' }, { name: 'm9' }] }
];
const value = 'm5';
const result = teams.map(t => {
const members = t.members.filter(d => d.name.toLowerCase().includes(value));
return { ...t, members };
})
console.log(result)
Check this. Instead of hard coded m5 pass your value.
const teams = [
{ name: 'Team1', members: [{ name: 'm1' }, { name: 'm2' }, { name: 'm3' }] },
{ name: 'Team2', members: [{ name: 'm4' }, { name: 'm5' }, { name: 'm6' }] },
{ name: 'Team3', members: [{ name: 'm7' }, { name: 'm8' }, { name: 'm9' }] }
];
const filteredTeams = teams.map(team => ({ name: team.name, members: team.members.filter(member => member.name.includes('m5')) }));
console.log(filteredTeams);
You are mutating the original objects, but you could assing new properties to the result object for mapping instead.
var teams = [{ name: 'Team1', members: [{ name: 'm1' }, { name: 'm2' }, { name: 'm3' }] }, { name: 'Team2', members: [{ name: 'm4' }, { name: 'm5' }, { name: 'm6' }] }, { name: 'Team3', members: [{ name: 'm7' }, { name: 'm8' }, { name: 'm9' }] }],
result = teams.map(o => Object.assign(
{},
o,
{ members: o.members.filter(({ name }) => name === 'm5') }
));
console.log(result);
console.log(teams);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try to seperate your filter function first:
const filterTeamMembers = (teams, filterArr) => {
const useFilter = filterArr.map(x => x.toLowerCase());
return teams.map(team => ({
...team,
members: team.members.filter(member => useFilter.includes(member.name))
}))
};
// =========== And then:
onSearchChange(event: any): void {
let value = event.target.value;
this.filteredTeams = filterTeamMembers(this.teams, [value]);
}

Categories

Resources