Necesito filtrar una matriz bidimensional en JS, sé que existe el acumulador, ¿podría explicarme cómo hacerlo, por favor?
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'}, ], } ];Resultado buscado después de filtrar por etiqueta '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 , itere sobre la matriz mientras actualiza una lista.Array#filter y String#includes , obtenga elementos cuya etiqueta incluya la cadena de destino. Si estos últimos existen, empuje un nuevo objeto al acumulador con category y items filtrados. 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);Otro enfoque es usar flatMap para que sirva como una combinación de filter y map , así:
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}Filtramos cada lista de elementos de la manera habitual y luego incluimos una matriz vacía, si el resultado filtrado está vacío, o una matriz que contiene una copia del objeto original con los resultados filtrados reemplazando a los originales.
Los parámetros _ y __ son solo marcadores de posición porque flatMap pasa parámetros de índice y matriz que queremos ignorar.
¡Me gusta el enfoque con reduce! Alternativamente, también podría hacer "filtro doble" (filtro anidado):
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'));