Подтвердить что ты не робот

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

Каков наилучший способ реорганизации array в output? Мне нужно объединить все ключи значений (независимо от того, массив или нет) в объекты, имеющие один и тот же ключ. Здесь есть что-то подобное , но это не отвечает на мой вопрос, потому что у меня также есть массивы.

var array = [
    {
        name: "foo1",
        value: "val1"
    }, {
        name: "foo1",
        value: [
            "val2",
            "val3"
        ]
    }, {
        name: "foo2",
        value: "val4"
    }
];

var output = [
    {
        name: "foo1",
        value: [
            "val1",
            "val2",
            "val3"
        ]
    }, {
        name: "foo2",
        value: [
            "val4"
        ]
    }
];

Да, я могу писать бесконечные циклы for и несколько массивов между ними, но есть ли простой (r) ярлык? Спасибо!

4b9b3361

Ответ 1

Не уверен, что есть лучший/более простой способ, но это сделало бы это: -

var array = [{
  name: "foo1",
  value: "val1"
}, {
  name: "foo1",
  value: ["val2", "val3"]
}, {
  name: "foo2",
  value: "val4"
}];

var output = [];

array.forEach(function(value) {
  var existing = output.filter(function(v, i) {
    return v.name == value.name;
  });
  if (existing.length) {
    var existingIndex = output.indexOf(existing[0]);
    output[existingIndex].value = output[existingIndex].value.concat(value.value);
  } else {
    if (typeof value.value == 'string')
      value.value = [value.value];
    output.push(value);
  }
});

console.dir(output);

Ответ 2

Вот еще один способ достижения этой цели:

var output = array.reduce(function(o, cur) {

  // Get the index of the key-value pair.
  var occurs = o.reduce(function(n, item, i) {
    return (item.name === cur.name) ? i : n;
  }, -1);

  // If the name is found,
  if (occurs >= 0) {

    // append the current value to its list of values.
    o[occurs].value = o[occurs].value.concat(cur.value);

  // Otherwise,
  } else {

    // add the current item to o (but make sure the value is an array).
    var obj = {name: cur.name, value: [cur.value]};
    o = o.concat([obj]);
  }

  return o;
}, []);

Ответ 3

Использование lodash

var array = [{name:"foo1",value:"val1"},{name:"foo1",value:["val2","val3"]},{name:"foo2",value:"val4"}];

function mergeNames (arr) {
    return _.chain(arr).groupBy('name').mapValues(function (v) {
        return _.chain(v).pluck('value').flattenDeep();
    }).value();
}

console.log(mergeNames(array));

Ответ 4

Попробуйте следующее:

var array = [{name:"foo1",value:"val1"},{name:"foo1",value:["val2","val3"]},{name:"foo2",value:"val4"},{name:"foo2",value:"val5"}];

for(var j=0;j<array.length;j++){
  var current = array[j];
  for(var i=j+1;i<array.length;i++){
    if(current.name = array[i].name){
      if(!isArray(current.value))
        current.value = [ current.value ];
      if(isArray(array[i].value))
         for(var v=0;v<array[i].value.length;v++)
           current.value.push(array[i].value[v]);
      else
        current.value.push(array[i].value);
      array.splice(i,1);
      i++;
    }
  }
}

function isArray(myArray) {
    return myArray.constructor.toString().indexOf("Array") > -1;
}

document.write(JSON.stringify(array));

Ответ 5

Использование сокращения:

var mergedObj = array.reduce((acc, obj) => {
    if (acc[obj.name]) {
       acc[obj.name].value = acc[obj.name].value.isArray ? 
       acc[obj.name].value.concat(obj.value) : 
       [acc[obj.name].value].concat(obj.value);

    } else {
      acc[obj.name] = obj;
    }

    return acc;
}, {});

let output = [];
for (let prop in mergedObj) {
  output.push(mergedObj[prop]) 
}