Создайте новый объект с уникальными элементами из объектов массива объектов

#javascript #arrays #object #javascript-objects #associative-array

Вопрос:

У меня есть множество объектов. Каждый объект в этом массиве имеет несколько ключевых пар. Одна из этих пар клавиш (например, «obj») также представляет собой массив объектов.

Пример того, что у меня есть:

 const arrOfObj = [
  { 
    "id": 1
    "obj": {
      "arr1": ["arr1-1"],
      "arr2": ["arr2-1", "arr2-2"],
      "arr3": ["arr3-1", "arr3-2"]
    }
  },
  { 
    "id": 1
    "obj": {
      "arr1": ["arr1-2"],
      "arr2": ["arr2-1", "arr2-3"],
      "arr3": ["arr3-1", "arr3-3"],
      "arr4": ["arr4-1"],
    }
  },
];
 

Мне нужно получить новый объект объектов «obj» с уникальными ключами и уникальными элементами внутри них.

Пример того, что мне нужно:

 const newObj = {
   "arr1": ["arr1-1", "arr1-2"],
   "arr2": ["arr2-1", "arr2-2", "arr2-3"],
   "arr3": ["arr3-1", "arr3-2", "arr3-3"],
   "arr4": ["arr4-1"],
}
 

Все это динамически поступает из API по запросу, поэтому я не знаю имен этих пар клавиш, но мне нужно их сохранить.

У меня есть решение, но я новичок в JavaScript и хочу знать, как упростить и улучшить мой плохой код.

1. Во-первых, я определяю новый объект и извлекаю имена для его пар клавиш из «arrOfObj».

 let filterObj = {};

arrOfObj.forEach(function (item) {
  for (let key in item.obj) {
    filterObj[key] = [];
  }
});
 

2. После этого я получаю все элементы каждого массива из «arrOfObj» и сохраняю их в новом объекте «filterObj» в паре клавиш с тем же именем.

 arrOfObj.forEach(function (item) {
  for (let key in item.obj) {
    for (let element = 0; element < item.obj[key].length; element  ) {
      filterObj[key].push(item.obj[key][element]);
    }
  }
});
 

3. До конца я фильтрую массивы, чтобы получить только уникальные элементы.

 for (let key in filterObj) {
  filterObj[key] = Array.from(new Set(filterObj[key]));
}
 

Это работает, у меня есть то, что я хочу, но это кажется чудовищным. Как этот код можно упростить наилучшим образом?

Спасибо за помощь и советы.

Комментарии:

1. В целом то, что у вас есть, неплохо, и это не код спагетти. Легко следовать каждому шагу. Есть некоторые ярлыки, такие как итерация Object.entries (), но возможность делать все это длинными руками, как вы это делали, является хорошим опытом обучения

2. @charlietfl Спасибо Тебе:) Но я хочу улучшить свой JS-навык, и я полностью уверен, что все это может и должно быть написано гораздо проще и лучше…

3. «Намного проще» … есть методы, которые, возможно, немного сгустят его, но тогда вы можете не найти его читаемым или доступным для обслуживания, если он не так ясен, как то, что у вас есть в настоящее время. Одно из предложений-использовать forEach() на втором шаге вместо более подробного for цикла

4. @charlietfl Понял, спасибо Тебе еще раз ^-^

5. И читайте о том , как Object.keys() это делается, Object.values() и Object.entries() работайте

Ответ №1:

Вы можете использовать некоторую деструкцию и Object.entries() и Object.keys (), чтобы упростить это и сделать все только для нового объекта

 const newObj  = {}

arrOfObj.forEach(({obj}) => {
    Object.entries(obj).forEach(([k, arr]) => {
       newObj[k] = newObj[k] || [];
       newObj[k].push(...arr);
    })
});

Object.keys(newObj).forEach(k => newObj[k] = [...new Set(newObj[k])]);

console.log(newObj) 
 <script>
const arrOfObj=[{id:1,obj:{arr1:["arr1-1"],arr2:["arr2-1","arr2-2"],arr3:["arr3-1","arr3-2"]}},{id:1,obj:{arr1:["arr1-2"],arr2:["arr2-1","arr2-3"],arr3:["arr3-1","arr3-3"],arr4:["arr4-1"]}}];
</script> 

Комментарии:

1. Очень элегантно. Я узнал много нового из этого фрагмента, спасибо ^-^

Ответ №2:

Другое решение, использующее Object#fromEntries , Array#reduce , Object#entries , Array#forEach Set , и Map :

 const arrOfObj = [ { "id": 1, "obj": { "arr1": ["arr1-1"], "arr2": ["arr2-1", "arr2-2"], "arr3": ["arr3-1", "arr3-2"] } }, { "id": 1, "obj": { "arr1": ["arr1-2"], "arr2": ["arr2-1", "arr2-3"], "arr3": ["arr3-1", "arr3-3"], "arr4": ["arr4-1"] } } ];

const filterObj = 
  // transform the resulting list of key-values pairs to an object at the end
  Object.fromEntries(
    // get a map of array name as key and its unique items as value
    [...arrOfObj.reduce((map, { obj = {} }) => {
      // iterate over current element's object to update the map
      Object.entries(obj).forEach(([currentKey, currentValues]) => {
        const keyValues = [...(map.get(currentKey) || []), ...currentValues];
        map.set(currentKey, [...new Set(keyValues)]);
      });
      return map;
    }, new Map)]
  );

console.log(filterObj); 

Комментарии:

1. Большое Вам спасибо, очень полезно и понятно!

2. @Агата, не за что. Обязательно прочитайте документы для лучшего понимания!