Преобразование объекта в группу на основе списка объектов массива

#javascript #arrays #object #grouping

#javascript #массивы #объект #группировка

Вопрос:

Я пытаюсь найти способ преобразовать этот список объектов на основе массива group. Сложная часть, которую я обнаружил, заключается в переборе массива групп и применении объекта к нескольким местам, если существует несколько групп.

Я также пытаюсь игнорировать любую группу, которая ни к чему не принадлежит. Я пытался использовать функцию reduce, но я не могу получить итерацию через массив group.

   let cars = 
    [
      {
        "group":[],
        "name": "All Makes",
        "code": ""
      },
      {
        "group":["Group A"],
        "name": "BMW",
        "code": "X821"
      },
      {
        "group":["Group B"],
        "name": "Audi",
        "code": "B216"
      },
      {
        "group":["Group B"],
        "name": "Ford",
        "code": "P385"    
      },
      {
        "group":["Group B", "Group C"],
        "name": "Mercedes",
        "code": "H801"
      },
      {
        "group":["Group C"],
        "name": "Honda",
        "code": "C213"
      }
    ]
  

Чтобы стать этим:

 [
    {
      "group": "Group A",
      "cars": [
         {
           name: "BMW",
           code: "X821"
         }
      ]
    },
    {
      "group": "Group B",
      "cars": [
         {
           name: "Audi",
           code: "B216"
         },
         {
           name: "Ford",
           code: "P385"
         },
         {
           name: "Mercedes",
           code: "H801"
         }
      ]
    },
    {
      "group": "Group C",
      "cars": [
         {
           name: "Mercedes",
           code: "H801"
         },
         {
           name: "Honda",
           code: "C213"
         }
      ]
    }

]
  

Я уже пробовал использовать reduce для достижения этой цели, но это не совсем дает желаемый эффект.

 const res = cars.reduce((acc, {group, ...r}) => {
  group.forEach(key => {
    acc[key] = (acc[key] || []).concat({...r}); 
  });
  return acc;
}, []);
console.log(res);
  

Ответ №1:

Использование строковых ключей в массивах работает не совсем хорошо, для этого и нужны объекты, затем используйте Object.values , чтобы извлечь из него массив. Также вы хотите поместить туда объекты, а не массивы:

  const res = Object.values(cars.reduce((acc, {group, ...r}) => {
    group.forEach(key => {
      (acc[key] = (acc[key] || { group, cars: [] })).cars.push(r);
    });
    return acc;
 }, {}));
  

Я бы написал это так:

   const byGroup = new Map();

  for(const { group, ...rest } of cars) {
     if(!byGroup.has(group))
       byGroup.set(group, { group, cars: [] });
     byGroup.get(group).cars.push(rest);
  }

  const result = [...byGroup.values()];
  

Ответ №2:

Вам нужно взять объект в качестве накопителя, а затем сопоставить записи для получения желаемого результата.

  let cars = [{ group: [], name: "All Makes", code: "" }, { group: ["Group A"], name: "BMW", code: "X821" }, { group: ["Group B"], name: "Audi", code: "B216" }, { group: ["Group B"], name: "Ford", code: "P385" }, { group: ["Group B", "Group C"], name: "Mercedes", code: "H801" }, { group: ["Group C"], name: "Honda", code: "C213" }],
    result = Object
        .entries(cars.reduce((acc, { group, ...r }) => {
            group.forEach(key => acc[key] = (acc[key] || []).concat({...r}));
            return acc;
         }, {}))
        .map(([group, cars]) => ({ group, cars }));

console.log(result);  
 .as-console-wrapper { max-height: 100% !important; top: 0; }