#javascript #filter
#javascript #Фильтр
Вопрос:
Я пытаюсь создать функцию фильтра, которая получает два аргумента: массив (который будет фильтроваться) и объект, который является критерием фильтрации.
Рассмотрим структуру массива как:
const items = [
{
category: "Social",
areasAffected: ["Area_01", "Area_02"],
},
{
category: "Environmental",
areasAffected: ["Area_01", "Area_02", "Area_03", "Area_04"],
}
];
и рассмотрим объект, как показано ниже:
const filters = {
category: [{ value: "Social", label: "Social" }],
areasAffected: [{ value: "Area_01", label: "Area_01" }]
}
и я определил функцию фильтра как:
const filterChallenges = (items, filters) => {
const filterKeys = Object.keys(filters);
return items.filter((item) => {
filterKeys.forEach((key) => {
if (!Array.isArray(item[key])) {
return item[key]
.toString()
.toLowerCase()
.includes(
filters[key].map((filterEle) =>
filterEle.value.toString().toLowerCase()
)
);
} else {
return item[key].map((arrEle) => {
arrEle
.toString()
.toLowerCase()
.includes(
filters[key].map((filterEle) =>
filterEle.value.toString().toLowerCase()
)
);
});
}
});
});
};
когда я запускаю функцию, она возвращает пустой массив. У кого-нибудь есть какие-либо предложения?
Ответ №1:
Сам код имеет две проблемы. Во-первых, forEach
не возвращает значение. Вы захотите использовать Array.every()
здесь, если хотите, чтобы ВСЕ фильтры совпадали. В противном случае вы захотите использовать Array.some()
.
Во-вторых, String.includes()
принимает не массив, а строку. Здесь вы захотите использовать Array.every()
снова, если хотите, чтобы ВСЕ элементы массива фильтра соответствовали значению, в противном случае используйте Array.some()
. Что касается else
ветки, которая обрабатывает значения элементов, которые являются массивами, вы захотите использовать Array.some()
, если хотите, чтобы ОДНО из значений массива совпадало.
const items = [
{
category: "Social",
areasAffected: ["Area_01", "Area_02"],
},
{
category: "Environmental",
areasAffected: ["Area_01", "Area_02", "Area_03", "Area_04"],
},
];
const filterChallenges = (items, filters) => {
const filterKeys = Object.keys(filters);
return items.filter((item) => {
// ALL of the filters must be matched (.every())
return filterKeys.every((filterKey) => {
if (!Array.isArray(item[filterKey])) {
const candidateValue = item[filterKey].toString().toLowerCase();
// ALL of the filter values must be included in the item value
// (.every())
return filters[filterKey].every((filterEle) =>
candidateValue.includes(filterEle.value.toString().toLowerCase())
);
}
// Value is an array, ONE element (.some()) must match ALL of the
// filter values (.every())
return item[filterKey].some((candidate) => {
const candidateValue = candidate.toString().toLowerCase();
return filters[filterKey].every((filterEle) =>
candidateValue.includes(filterEle.value.toString().toLowerCase())
);
});
});
});
};
const ret = filterChallenges(items, {
category: [{ value: "Social", label: "Social" }],
areasAffected: [{ value: "Area_01", label: "Area_01" }],
});
console.log(ret);
Кроме того, если все ваши значения являются строками, .toString()
является избыточным.