фильтровать массив объектов на основе объекта с массивом в качестве значения его свойства в react

#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() является избыточным.