Объедините два объекта в массиве в один объект, если свойства объекта совпадают, и преобразуйте уникальные свойства в массив

Вход -

[
  {color:'red', shape:'circle', size:'medium'},
  {color:'red', shape:'circle', size:'small'}
]

Выход -

[
  {color:'red', shape:'circle', size:['medium','small']}
]

Как это может быть достигнуто в Javascript?

Вы хотите, чтобы [ {цвет: 'красный', форма: 'квадрат', размер: 'маленький'}, {цвет: 'красный', форма: 'круг', размер: 'маленький'}] выводился [ {цвет: 'red', shape:['circle', 'square'], size:'small'} ] и как бы вы поступили в случае, когда есть три объекта, и все они соответствуют двум общим, но не одинаковым две вещи? Будет ли когда-нибудь только два предмета?

Cal Irvine 30.05.2019 18:02

Да, я ищу идеальное решение, которое может обрабатывать повторяющиеся свойства в объектах.

Gokkul 30.05.2019 18:10

Но тогда, как говорит @Cal Irvine, что вы ожидаете получить на выходе, когда ввод выглядит примерно так: [ {color:'red', shape:'circle', size:'medium'}, {color:'red', shape:'circle', size:'small'}, {color:'red', shape:'square', size:'small'}, {color:'blue', shape:'circle', size:'medium'}]? Как вы будете группировать предметы?

Shidersz 30.05.2019 18:15

Возможный дубликат Группировать элементы массива с помощью объекта

Heretic Monkey 30.05.2019 18:28

В этом случае я ожидал бы вывода [ {цвет: «красный», форма: «круг», размер: [«средний», «маленький»]}, {цвет: «красный», форма: «квадрат», размер :'маленький'}, {цвет:'синий', форма:'круг', размер:'средний'}]

Gokkul 30.05.2019 19:39
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
5
134
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете создать общую функцию, которая принимает в качестве параметров массив объектов и массив ключей.

Вы можете сделать это, выполнив следующие действия:

  • Сначала используйте reduce() для массива объектов и установите аккумулятор в пустой массив []
  • Получите другие реквизиты (уникальные реквизиты), используя filter() на Object.keys()
  • Затем на каждой итерации найдите элемент массива аккумуляторов, все заданные реквизиты которого совпадают с текущим объектом.
  • Если элемент найден, используйте forEach() другие клавиши и поместите значения в соответствующий массив.
  • Если элемент не найден, установите для каждого ключа пустой массив.
  • Наконец верните результат reduce()

const arr = [
  {color:'red', shape:'circle', size:'medium'},
  {color:'red', shape:'circle', size:'small'}
]

function groupByProps(arr,props){
  const res = arr.reduce((ac,a) => {
    let ind = ac.findIndex(b => props.every(k => a[k] === b[k]));
    let others = Object.keys(a).filter(x => !props.includes(x));
    if (ind === -1){
      ac.push({...a});
      others.forEach(x => ac[ac.length - 1][x] = []);
      ind = ac.length - 1
    }
    others.forEach(x => ac[ind][x].push(a[x]));
    return ac;
  },[])
  return res;
}

const res = groupByProps(arr,['color','shape'])
console.info(res)
Ответ принят как подходящий

Если вы просто хотите сгруппировать на основе color и shape, вы можете использовать reduce. Создайте объект-аккумулятор с каждой уникальной комбинацией этих двух свойств, разделенных ключом |. И объект, который вы хотите на выходе, как их значение. Затем используйте Object.values(), чтобы получить эти объекты в виде массива.

const input = [
  {color:'red', shape:'circle', size :'medium'},
  {color:'red', shape:'circle', size:'small'},
  {color:'blue', shape:'square', size:'small'}
];

const merged = input.reduce((acc, { color, shape, size }) => {
  const key = color + "|" + shape;
  acc[key] = acc[key] || { color, shape, size: [] };
  acc[key].size.push(size);
  return acc
}, {})

console.info(Object.values(merged))

Вот как выглядит объединенный/аккумулятор:

{
  "red|circle": {
    "color": "red",
    "shape": "circle",
    "size": [
      "medium",
      "small"
    ]
  },
  "blue|square": {
    "color": "blue",
    "shape": "square",
    "size": [
      "small"
    ]
  }
}

Вы можете сделать его динамическим, создав массив ключей, которые вы хотите сгруппировать:

const input = [
      { color: 'red', shape: 'circle', size: 'medium' },
      { color: 'red', shape: 'circle', size: 'small' },
      { color: 'blue', shape: 'square', size: 'small' }
   ];
const groupKeys = ['color', 'shape'];

const merged = input.reduce((acc, o) => {
  const key = groupKeys.map(k => o[k]).join("|");
  
  if (!acc[key]) {
    acc[key] = groupKeys.reduce((r, k) => ({ ...r, [k]: o[k] }), {});
    acc[key].size = []
  }
  
  acc[key].size.push(o.size)
  return acc
}, {})

console.info(Object.values(merged))

Вот простая функция groupBy, которая принимает массив объектов и массив props для группировки:

let data = [
  {color:'red', shape:'circle', size:'medium'},
  {color:'red', shape:'circle', size:'small'}
]

let groupBy = (arr, props) => Object.values(arr.reduce((r,c) => {
  let key = props.reduce((a,k) => `${a}${c[k]}`, '')
  let otherKeys = Object.keys(c).filter(k => !props.includes(k))
  r[key] = r[key] || {...c, ...otherKeys.reduce((a,k) => (a[k] = [], a),{})}
  otherKeys.forEach(k => r[key][k].push(c[k]))
  return r
}, {}))

console.info(groupBy(data, ['color','shape']))

Идея состоит в том, чтобы использовать Массив.уменьшить и, по сути, создать строковый ключ переданного реквизита. Для других полей создайте массив и сохраняйте туда значения на каждой итерации.

Другие вопросы по теме