G
G
groulls2020-10-06 13:42:21
JavaScript
groulls, 2020-10-06 13:42:21

Filtering nested React data?

How can one correctly filter an array of objects of such a plan:

let arr = [{
    "category": "new",
    "list": [{
        "item": "Black"
      },
      {
        "item": "Red"
      }
    ]
  },
  {
    "category": "old",
    "list": [{
        "item": "..."
      },
      {
        "item": "...."
      }
    ]
  }

What would be the output after filtering to receive such a plan, depending on the entered category or item, while if only category is entered, display the entire item inside, if the item is entered, display all the category where this item occurs and the items themselves, so that further them in 2- x components could be mapped by category , and then by item. I'm writing something like this now:
с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)))


But I get the output if the input value is empty
[
[{"id":126,"item":"...."},{"id":127,"item":"...."},{"id":133,"item":"....""}],
[{"id":129,"item":"...."},{"id":130,"item":"...."}],
[{"id":131,"item":"....""},{"id":132,"item":"...."}]
]

Answer the question

In order to leave comments, you need to log in

2 answer(s)
R
Roman Yakimchuk, 2020-10-06
@yakimchuk-ry

I would make two dictionaries (sets of data correspondences):
1. Category name => Category
2. Item name => All categories with this Item
Next, when filtering, it will be enough to check for the presence of a key in any dictionary (this way you will understand if a category or Item is entered), and return value by key.
Dictionaries can be compiled once when data is received.
Everything written above, provided that I correctly understood what you need J

A
Aetae, 2020-10-06
@Aetae

1. An empty string occurs in any line, so such a search returns all values.
2. mapAdds the result of the passed function into the output array. Since it returns a filtered array itemsfor you, you end up with an array of arrays items. If you need categories to be returned, return categories.
Well, you don’t need to do the same job twice, you can get by with one 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[])
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question