Объединить сам массив в другой массив с тем же ключом в javascript

#javascript #arrays #algorithm #typescript #object

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

Вопрос:

Я пытаюсь объединить сам массив и преобразовать его в более значимый массив

 array = [
{item: 'pen', madeIn: 'US', color: 'blue'},
{item: 'pen', madeIn: 'US', color: 'white'},
{item: 'pen', madeIn: 'China', color: 'red'},
{item: 'pen', madeIn: 'China', color: 'white'}
]
  

выходной массив, который я хочу создать :

 outputArray = [
{item: 'pen', madeIn: 'US', color: ['blue', 'white']},
{item: 'pen', madeIn: 'China', color: ['red', 'white']}
];
  

Я пытался, но безуспешно, единственное решение, которое я могу придумать на данный момент, — это использование временной переменной для хранения элемента и значения madeIn. и запустить другой цикл для сравнения item и madeIn, а затем добавить цвет в массив. Существует несколько циклов для решения этой проблемы.

Я имею в виду, что он выполняет свою работу, но определенно не является оптимальным решением. любой другой идеал будет приветствоваться. Спасибо.

Ответ №1:

Уменьшите массив до объекта, используя свойства item и madeIn для создания ключа. Для каждого объекта проверьте, существует ли ключ уже, и, если нет, создайте новый объект для ключа со свойством color в виде пустого массива. Вставьте color каждый объект в массив. Используется Object.values() для преобразования объекта в массив.

 const array = [{"item":"pen","madeIn":"US","color":"blue"},{"item":"pen","madeIn":"US","color":"white"},{"item":"pen","madeIn":"China","color":"red"},{"item":"pen","madeIn":"China","color":"white"}]

const result = Object.values(
  array.reduce((r, o) => {
    const key = `${o.item}-${o.madeIn}`
    
    if(!r[key]) r[key] = { ...o, color: [] }
    
    r[key].color.push(o.color)
    
    return r;
  }, {})
)

console.log(result)  

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

1. Не могли бы вы объяснить, как работает ключ с переносом? Я не понимаю, как работает ключ.

2. Я просто играл на консоли и понял, что вы начали с объекта для своего аккумулятора, а затем получили ключи для конечного результата. Это решение недопустимо, поскольку ключи объекта не гарантированно находятся в каком-либо определенном порядке, поэтому, если порядок важен, это недопустимое решение.

3. @AdrianBrand — ES6 фактически определил порядок обхода для ключей объектов. Основная идея заключается в том, что целочисленные ключи перемещаются по их числовому порядку, в то время как строковые ключи перемещаются в порядке вставки. Итак, мое решение сохраняет первоначальный порядок. Подробнее об этом читайте в этой статье .

4. Ключ с переносом работает, потому что подобный ключ pen-blue достаточно уникален в текущем случае для работы. Если нет, вы можете использовать другой разделитель или комбинацию исходных ключей.

5. Полезно знать, что строковые ключи перемещаются по порядку вставки. ES5 это не было гарантировано, поэтому было несколько случаев, когда я не использовал ключи объектов, но если бы я знал, что ES6 гарантирует сохранение порядка вставки. Спасибо, сегодня я узнал кое-что полезное.

Ответ №2:

Используйте reduce :

 const array = [{ item: 'pen', madeIn: 'US', color: 'blue' }, { item: 'pen', madeIn: 'US', color: 'white' }, { item: 'pen', madeIn: 'China', color: 'red' }, { item: 'pen', madeIn: 'China', color: 'white' }];

const output = Object.values(array.reduce((acc, { item, madeIn, color}) => {
  acc[`${item}-${madeIn}`] = acc[`${item}-${madeIn}`] || { item, madeIn, color: [] };
  acc[`${item}-${madeIn}`].color.push(color);
  return acc;
}));

console.log(output);  

Ответ №3:

Вот решение, которое использует Array.prototype.reduce() и деструктурирование объекта:

 const initialArray = [
  {item: 'pen', madeIn: 'US', color: 'blue'},
  {item: 'pen', madeIn: 'US', color: 'white'},
  {item: 'pen', madeIn: 'China', color: 'red'},
  {item: 'pen', madeIn: 'China', color: 'white'}
];

const finalArray = initialArray.reduce((accumulator, currentValue) => {
  const item = accumulator.find(x => x.item === currentValue.item amp;amp; x.madeIn === currentValue.madeIn);
  if(item) {
    item.color.push(currentValue.color);
  }
  else {
    accumulator.push({...currentValue, color: [currentValue.color]});
  }
  return accumulator; 
}, []);

console.log(finalArray);  

В отличие от других ответов, это не основано на «не таком уникальном» ключе и будет работать для любых данных.