@groulls

Фильтрация вложенных данных React?

Как можно корректно отфильтровать массив объектов такого плана:
let arr = [{
    "category": "new",
    "list": [{
        "item": "Black"
      },
      {
        "item": "Red"
      }
    ]
  },
  {
    "category": "old",
    "list": [{
        "item": "..."
      },
      {
        "item": "...."
      }
    ]
  }

Что бы на выходе после фильтрации получать такого плана в зависимости от введеной category или item, при это если введена только category отобразить внутри все item, если введен item, отобразить все category где этот item встречается и сами item, что бы дальше их в 2-х комопнентах можно было мапить по category , а потом по item. Пишу сейчас что то типа такого:
сonst filterData = arr
    .filter(
      (value) =>
        value.category.toLowerCase().includes(input.value) ||
        value.list.some((i: any) => i.item.toLowerCase().includes(input.value))

    ).map(e=>e.list.filter(e=>e.item.toLowerCase().includes(input.value)))


Но на выходе получаю, если input value пустое
[
[{"id":126,"item":"...."},{"id":127,"item":"...."},{"id":133,"item":"....""}],
[{"id":129,"item":"...."},{"id":130,"item":"...."}],
[{"id":131,"item":"....""},{"id":132,"item":"...."}]
]
  • Вопрос задан
  • 479 просмотров
Пригласить эксперта
Ответы на вопрос 2
Я бы сделал два словаря (наборов соответствий данных):
1. Название категории => Категория
2. Название Item => Все категории с этим Item

Дальше при фильтрации достаточно будет проверить наличие ключа в любом словаре (так вы поймете введена категория или Item), и вернуть значение по ключу.

Словари можно составить один раз при получении данных.
Всё написанное выше при условии что я правильно понял что вам нужно J
Ответ написан
Комментировать
Aetae
@Aetae Куратор тега JavaScript
Тлен
1. В любой строке встречается пустая строка, по этому такой поиск выдаёт все значения.
2. map складывает в выходной массив результат переданной функции. Поскольку она у вас возвращает отфильтрованный массив items, то в итоге у вас получается массив массивов items. Если вам нужно, чтоб возвращались категории - возвращайте категории.

Ну и дважды одну и ту же работу делать не надо, можно обойтись одним reduce:
сonst filterData = filter(arr, input.value);

interface Category {
  category: string;
  list: Array<{
    item: string;
  }>;
}

function filter<T extends Category>(data: T[], value: string): T[] {
  if (!value) return data.slice(); // или [] если при пустом value нужен пустой массив
  value = value.toLowerCase();
  
  return data.reduce((result, category) => {
    if(category.category.toLowerCase().includes(value)) {
      result.push(category);
    } else {
      const list = category.list.filter(({ item }) => item.toLowerCase().includes(value));
      if (list.length) {
        result.push({
          ...category,
          list
        });
      }
    }
    return result;
  }, [] as T[])
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы