I need to filter a two dimensional array in JS, I know there is the accumulator could you explain me how to do it please
let listItems = [
{
category: false,
items: [
{ value: 1, label: 'Disabled'},
{ value: 2, label: 'Carole Poland'},
{ value: 3, label: 'Wanda Howard'},
],
},
{
category: 'Suggestions',
items: [
{ value: 4, label: 'Robin Counts'},
{ value: 5, label: 'Alex Doe'},
],
},
{
category: 'Batiment',
items: [
{ value: 6, label: 'Vincent Howi'},
{ value: 7, label: 'Alex Zusk'},
],
}
];
Wanted result after filter by label 'Alex'
let listItems = [
{ category: 'Batiment', items: [{ value: 7, label: 'Alex Zusk'}] },
{ category: 'Suggestions', items: [{ value: 5, label: 'Alex Doe'}] }
];
<input
type="text"
id="myInput"
onkeyup="myFunction()"
placeholder="Search.."
/>
function myFunction() {
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
console.log('Search :', filter);
}
Array#reduce, iterate over the array while updating a list.Array#filter and String#includes, get items whose label includes the target string. If the latter exist, push a new object to the accumulator with category and filtered items.const listItems = [
{
category: false,
items: [ { value: 1, label: 'Disabled'}, { value: 2, label: 'Carole Poland'}, { value: 3, label: 'Wanda Howard'} ]
},
{
category: 'Suggestions',
items: [ { value: 4, label: 'Robin Counts'}, { value: 5, label: 'Alex Doe'} ]
},
{
category: 'Batiment',
items: [ { value: 6, label: 'Vincent Howi'}, { value: 7, label: 'Alex Zusk'} ]
}
];
const target = 'Alex';
const filteredListItems = listItems.reduce((list, { category, items = [] }) => {
const filteredItems = items.filter(({ label }) => label.includes(target));
if(filteredItems.length > 0) { list.push({ category, items: filteredItems }); }
return list;
}, []);
console.log(filteredListItems);
Another approach is using flatMap to serve as a combination of filter and map, like this:
const byLabel = (xs) => (target) => xs .flatMap (
({items, ...rest}, _, __,
filteredItems = items .filter (({label}) => label .includes (target))
) => filteredItems .length ? [{...rest, items: filteredItems}] : [])
const listItems = [{category: false, items: [{value: 1, label: "Disabled"}, {value: 2, label: "Carole Poland"}, {value: 3, label: "Wanda Howard"}]}, {category: "Suggestions", items: [{value: 4, label: "Robin Counts"}, {value: 5, label: "Alex Doe"}]}, {category: "Batiment", items: [{value: 6, label: "Vincent Howi"}, {value: 7, label: "Alex Zusk"}, {value: 8, label: "Alex Again"}]}]
console .log (byLabel (listItems) ('Alex'))
.as-console-wrapper {max-height: 100% !important; top: 0}
We filter each list of items in the usual manner, and then we include either an empty array, if the filtered result is empty, or an array containing a copy of the original object with the filtered results replacing the original ones.
The _, and __ parameters are just placeholder because flatMap passes index and array parameters we want to ignore.
I like the approach with reduce! Alternatively you could also do "double filter" (nested filter):
function getItemsByLabel(listItems, label) {
return listItems.filter((item) => {
const filtered = item.items.filter((inner) => {
return inner.label.toLowerCase().indexOf(label.toLowerCase()) >= 0;
});
if (filtered.length) {
item.items = filtered;
};
return filtered.length;
})
}
console.log(getItemsByLabel(listItems, 'alex'));