Как сгруппировать объекты по вложенным дочерним объектам массива в массиве - PullRequest
1 голос
/ 04 апреля 2020

У меня возникла небольшая проблема, которую пытались обуздать под ковром.

Я вызываю API, являющийся продуктом, у каждого продукта есть ключ categories со значением массива. карт. Пытаясь классифицировать их по категориям.

Это мой пример ответа от API

[
  {
    "name": "Product one",
    "categories": [
      {
        "id": 1,
        "name": "Category One"
      }
    ]
  },
  {
    "name": "Product Two",
    "categories": [
      {
        "id": 1,
        "name": "Category One"
      },
      {
        "id": 2,
        "name": "Category two"
      }
    ]
  }
]

Код, который я написал ниже:

 function groupBy(arr) {
      let categories = [];
      arr.forEach(el => {
        el.categories.forEach(c => {
          // Skapa ny kategori om inte redan existerar
          if (!categories.includes(c.id)) {
            categories.push({
              name: c.name,
              id: c.id,
              products: [el]
            });
          } else {
            // Lägg till produkt i existerande kategori
            categories.forEach(_c => {
              if (_c.id === c.id) {
                _c.products.push(el)
              }
            })
          }
        });
      });

      return categories;
    }

groupBy(arr);

Я думаю, что я Я как-то переусердствовал, желаемый результат, конечно, без каких-либо дублирующих категорий, продукты должны быть помещены в products[].

Screenshot of console output in Chrome browser

Ответы [ 2 ]

2 голосов
/ 04 апреля 2020

Использование map-reduce может быть сделано.

const data = [{"name":"Product one","categories":[{"id":1,"name":"Category One"}]},{"name":"Product Two","categories":[{"id":1,"name":"Category One"},{"id":2,"name":"Category two"}]}];

function categoriesList(list = []) {
  return Object.values(
    list.reduce((arr, product) => {
      product.categories.forEach((cat) => {
        if (!arr[cat.id]) arr[cat.id] = { ...cat, products: [] };
        arr[cat.id].products.push(product);
      });
      return arr;
    }, {})
  );
}
console.log(JSON.stringify(categoriesList(data), null, 4));
.as-console {
  min-height: 100% !important;
}

.as-console-row {
  color: blue !important;
}
1 голос
/ 04 апреля 2020

Вы можете сделать это, сначала пройдя по продуктам, чтобы назначить их каждой из категорий. Для предотвращения дублирования вы хотите использовать карту или набор; здесь я использую javascript объект в качестве карты. Когда у вас есть это, вы можете преобразовать его в массив, как вы хотите, используя Object.values ​​() на объекте карты

const groupProductsByCategory = (products) => {
  // reduce down each product into a category map
  const productsGroupedByCategory = products.reduce((categories, product) => {
    // insert the current product into each of the categories it contains
    product.categories.forEach(category => {
      // if the category exists in the map, we just need to append the current product
      if (category.id in categories)
        categories[category.id].products.push(product)
      else // otherwise, create a new category object with the current product
      categories[category.id] = ({ ...category, products: [product] })
    })
    return categories
  }, ({}))

  // convert the object into an array of objects
  return Object.values(productsGroupedByCategory)
}
...