Как объединить / объединить значения одинаковых свойств объекта в массиве объектов, используя lodash? - PullRequest
0 голосов
/ 03 января 2019

У меня есть массив массивов объектов, который выглядит следующим образом:

let fruitSamples = [
  [
    {'id': 1,'type': 'apples','samples': [1, 2, 3]},
    {'id': 2,'type': 'bananas','samples': [1, 2, 7]},
    {'id': 3,'type': 'pears','samples': [1, 2, 3]}
  ],
  [
    {'id': 1,'type': 'apples','samples': [5, 2, 9]},
    {'id': 2,'type': 'bananas','samples': [1, 7, 7]},
    {'id': 3,'type': 'pears','samples': [12, 21, 32]}
  ],
  [
    {'id': 1,'type': 'apples','samples': [11, 2, 33]},
    {'id': 2,'type': 'bananas','samples': [17, 2, 67]},
    {'id': 3,'type': 'pears','samples': [91, 22, 34]}
  ]
];

Я хочу уменьшить и объединить вышеуказанный массив, используя lodash, в один, чтобы сэмплы соединялись вместе следующим образом:

fruitSamples = [
  {'id': 1, 'type': 'apples', 'samples': [1,2,3,5,2,9,11,2,33]},
  {'id': 2, 'type': 'bananas', 'samples': [1,2,7,1,7,7,17,2,67]},
  {'id': 3, 'type': 'pears', 'samples': [1,2,3,12,21,32,91,22,34]},
]

Я испробовал много разных подходов, но так как я хочу кратчайший путь решения этой проблемы, что бы вы посоветовали?

Я пробовал это:

let test = _(fruitSamples)
  .flatten()
  .groupBy('type')
  .map(_.spread(_.merge))
  .value();

console.log(test);

Это дает мне следующий результат, который не объединяет образцы:

test = [
  {'id': 1,'type': 'apples','samples': [11, 2, 33]},
  {'id': 2,'type': 'bananas','samples': [17, 2, 67]},
  {'id': 3,'type': 'pears','samples': [91, 22, 34]}
]

Я чувствую, что использование _.mergeWith может быть правильным ответом, если да, я ищу помощь в реализации mergeWith в лучшем виде, так как я не уверен, как это сделать. Есть предложения?

Ответы [ 4 ]

0 голосов
/ 03 января 2019

Один из способов сделать это с помощью JavaScript и без кода:

var fruitSamples = [
[
   {'id': 1,'type': 'apples','samples': [1, 2, 3]},
   {'id': 2,'type': 'bananas','samples': [1, 2, 7]},
   {'id': 3,'type': 'pears','samples': [1, 2, 3]}
],
[
   {'id': 1,'type': 'apples','samples': [5, 2, 9]},
   {'id': 2,'type': 'bananas','samples': [1, 7, 7]},
   {'id': 3,'type': 'pears','samples': [12, 21, 32]}
],
[
   {'id': 1,'type': 'apples','samples': [11, 2, 33]},
   {'id': 2,'type': 'bananas','samples': [17, 2, 67]},
   {'id': 3,'type': 'pears','samples': [91, 22, 34]}
 ]
 ];

var test = fruitSamples.flat().reduce((rv,x)=>{
  var f = rv.find(y => y.id == x.id);
  if(f == null){
        f ={"id":x.id, "type":x.type,"samples":x.samples};
        rv.push(f);
  }
  else{
     f.samples = f.samples.concat(x.samples);
  }
  return rv;
},[]);
console.log(JSON.stringify(test))

https://jsfiddle.net/pimboden40/y8x96sbg/1/

0 голосов
/ 03 января 2019

Вы можете сначала преобразовать массив или массивы в простой массив, используя .reduce, а затем сгруппировать, снова используя .reduce.

Может быть прощезахватить

Что-то вроде

let fruitSamples = [
  [
    {'id': 1,'type': 'apples','samples': [1, 2, 3]},
    {'id': 2,'type': 'bananas','samples': [1, 2, 7]},
    {'id': 3,'type': 'pears','samples': [1, 2, 3]}
  ],
  [
    {'id': 1,'type': 'apples','samples': [5, 2, 9]},
    {'id': 2,'type': 'bananas','samples': [1, 7, 7]},
    {'id': 3,'type': 'pears','samples': [12, 21, 32]}
  ],
  [
    {'id': 1,'type': 'apples','samples': [11, 2, 33]},
    {'id': 2,'type': 'bananas','samples': [17, 2, 67]},
    {'id': 3,'type': 'pears','samples': [91, 22, 34]}
  ]
];

var merged = fruitSamples.reduce(function(prev, next) {
  return prev.concat(next);
});

var res = merged.reduce(function(prev, next) {
      
      var index = prev.findIndex(o=> o.id == next.id) 
         if(index >= 0)
           prev[index].samples = [...prev[index].samples,...next.samples];
           else
           prev.push(next);
           
           return prev;
},[]);

console.log(res)
0 голосов
/ 03 января 2019

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

Из Официальные документы :

Этот метод похож на _.merge, за исключением того, что он принимает настройщик, который вызывается для создания объединенных значений свойств назначения и источника.

let fruitSamples = [
  [
    {'id': 1,'type': 'apples','samples': [1, 2, 3]},
    {'id': 2,'type': 'bananas','samples': [1, 2, 7]},
    {'id': 3,'type': 'pears','samples': [1, 2, 3]}
  ],
  [
    {'id': 1,'type': 'apples','samples': [5, 2, 9]},
    {'id': 2,'type': 'bananas','samples': [1, 7, 7]},
    {'id': 3,'type': 'pears','samples': [12, 21, 32]}
  ],
  [
    {'id': 1,'type': 'apples','samples': [11, 2, 33]},
    {'id': 2,'type': 'bananas','samples': [17, 2, 67]},
    {'id': 3,'type': 'pears','samples': [91, 22, 34]}
  ]
];

function customizer(objValue, srcValue) {
  if (_.isArray(objValue)) {
    return objValue.concat(srcValue);
  }
}

let test = _(fruitSamples)
  .flatten()
  .groupBy('type')
  .map(_.spread((...values) => {
    return _.mergeWith(...values, customizer);
  }))
  .value();
  
console.log(test);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
0 голосов
/ 03 января 2019

Не знаю, как это сделать, используя lodash, но для чистого Javascript это не так уж сложно.

Обновление: благодаря @Taki выполнение flat() сначала делает это еще проще ..

let fruitSamples = [[{"id":1,"type":"apples","samples":[1,2,3]},{"id":2,"type":"bananas","samples":[1,2,7]},{"id":3,"type":"pears","samples":[1,2,3]}],[{"id":1,"type":"apples","samples":[5,2,9]},{"id":2,"type":"bananas","samples":[1,7,7]},{"id":3,"type":"pears","samples":[12,21,32]}],[{"id":1,"type":"apples","samples":[11,2,33]},{"id":2,"type":"bananas","samples":[17,2,67]},{"id":3,"type":"pears","samples":[91,22,34]}]];

let concat = fruitSamples.flat().reduce((a, i) => {
  const f = a.find(f => f.id === i.id);
  if (!f) a.push(i);
  else f.samples = [...f.samples, ...i.samples];
  return a;
}, []);

console.log(concat);
...