Filtering nested React data?

  • 0
    How can you correctly filter an array of objects of this kind:
    let arr = [{
        "category": "new",
        "list": [{
            "item": "Black"
          },
          {
            "item": "Red"
          }
        ]
      },
      {
        "category": "old",
        "list": [{
            "item": "..."
          },
          {
            "item": "...."
          }
        ]
      }

    So that after filtering, after filtering, to receive such a plan depending on the entered category or item, while if only category is entered, display all item inside, if item is entered, display all categories where this item occurs and the item itself, what would be further in 2- x components could be mapped by category, and then by item. Now I am writing something like this:
    с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 at the output I get 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":"...."}]
    ]
    JavaScript Anonymous, Feb 8, 2020

  • 2 Answers
  • 0
    I would make two dictionaries (datasets):

    1. Category name = & gt; Category

    2. Item name = & gt; All categories with this Item



    Further, when filtering, it will be enough to check for the presence of a key in any dictionary (so you will understand that a category or Item is entered), and return the value by the key.



    Dictionaries can be compiled once when receiving data.

    Everything written above, provided that I understand correctly that you need J
    Anonymous

  • 0
    1. Any line contains an empty string, so this search will return all values.

    2. map adds the result of the passed function to the output array. Since it returns a filtered items array for you, you end up with an array of items arrays. If you need categories to return, return categories.



    Well, you don't need to do the same work twice, you can do 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[])
    }
    Anonymous

Your Answer
To place the code, please use CodePen or similar tool. Thanks you!