2

Suppose I have the following array of objects:

var list = [
  { a: 1, 
    b: { c: 'x', k: []}
  },
  { a: 1,
    b: {c: 'x', d: 8}
  }
];

I want them to be merged into one "generic" object, for this example, it would be:

{a: 1, b: {c: 'x', d:'8', k[]}}

As you can see, all nested objects are merged too. But I can't gain it. If I use Object.assign it creates new nested objects if they are different, that is duplicates them:

var res = Object.assign({}, ...list);
// res: {
    a: 1, 
    b: {c: 'x', k: []},
    b: {c: 'x', d: 8}
}
1

3 Answers 3

2

You could try the following using the reduce method:

var list = [{
  a: 1,
  b: {
    a: 4,
    k: 3
  }
}, {
  a: 1,
  s: 11,
  b: {
    ab: 4,
    d: 8
  }
}]

var result = list.reduce(function(acc, item) {
  var obj = { ...item
  }
  Object.keys(obj).forEach(function(item) {
    if (acc[item]) { //if a property with the the key, 'item' already exists, then append to that
      Object.assign(acc[item], obj[item]);
    } else { // else add the key-value pair to the accumulator object.
      acc[item] = obj[item];
    }
  })
  return acc;
}, {})

console.log(result);

Sign up to request clarification or add additional context in comments.

2 Comments

This code actually has a bug. As soon as a nested object starts from different field it stops working: [ {a: 1, b: {a: 4, k: 3} }, {a: 1, s:11, b: {ab: 4, d: 8} } ]
My mistake. Just edited the code. Please see if it works for you
1

Deep merging is not simple to do yourself, That blog uses deep merge.

If you don't have webpack or nodejs you can use deepmerge like so:

// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25
var canUseSymbol = typeof Symbol === 'function' && Symbol.for
var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7

function isReactElement(value) {
	return value.$$typeof === REACT_ELEMENT_TYPE
}

function isNonNullObject(value) {
	return !!value && typeof value === 'object'
}

function isSpecial(value) {
	var stringValue = Object.prototype.toString.call(value)

	return stringValue === '[object RegExp]'
		|| stringValue === '[object Date]'
		|| isReactElement(value)
}

function defaultIsMergeableObject(value) {
	return isNonNullObject(value)
		&& !isSpecial(value)
}



function emptyTarget(val) {
	return Array.isArray(val) ? [] : {}
}

function cloneUnlessOtherwiseSpecified(value, options) {
	return (options.clone !== false && options.isMergeableObject(value))
		? deepmerge(emptyTarget(value), value, options)
		: value
}

function defaultArrayMerge(target, source, options) {
	return target.concat(source).map(function(element) {
		return cloneUnlessOtherwiseSpecified(element, options)
	})
}

function mergeObject(target, source, options) {
	var destination = {}
	if (options.isMergeableObject(target)) {
		Object.keys(target).forEach(function(key) {
			destination[key] = cloneUnlessOtherwiseSpecified(target[key], options)
		})
	}
	Object.keys(source).forEach(function(key) {
		if (!options.isMergeableObject(source[key]) || !target[key]) {
			destination[key] = cloneUnlessOtherwiseSpecified(source[key], options)
		} else {
			destination[key] = deepmerge(target[key], source[key], options)
		}
	})
	return destination
}

function deepmerge(target, source, options) {
	options = options || {}
	options.arrayMerge = options.arrayMerge || defaultArrayMerge
	options.isMergeableObject = options.isMergeableObject || defaultIsMergeableObject

	var sourceIsArray = Array.isArray(source)
	var targetIsArray = Array.isArray(target)
	var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray

	if (!sourceAndTargetTypesMatch) {
		return cloneUnlessOtherwiseSpecified(source, options)
	} else if (sourceIsArray) {
		return options.arrayMerge(target, source, options)
	} else {
		return mergeObject(target, source, options)
	}
}

deepmerge.all = function deepmergeAll(array, options) {
	if (!Array.isArray(array)) {
		throw new Error('first argument should be an array')
	}

	return array.reduce(function(prev, next) {
		return deepmerge(prev, next, options)
	}, {})
}
var list = [{
  a: 1,
  b: {
    c: 'x',
    //merging 1,2 and 1,3 results in [1,2,1,3] you can change that in defaultArrayMerge
    k: [1,2]
  }
},
{
  a: 1,
  b: {
    c: 'x',
    k: [1,3],
    d: 8
  }
}];

console.log(
  deepmerge.all(list)
)

Comments

-1

You can use the reduce method. Remove the first element from the original list , that object will be the base method.

var list = [{
    a: 1,
    b: {
      c: 'x',
      k: []
    }
  },
  {
    a: 1,
    b: {
      c: 'x',
      d: 8
    }
  }
];
// Remove the first element from the array. The first element will be
// the base object
// slice will return a new array without the first object
// apply reduce on this list
let _temp = list.slice(1);
let x = _temp.reduce(function(acc,curr,currIndex){
    for(let keys in curr){
      // checking if the base object have the same key as of current object
      if(acc.hasOwnProperty(keys)){
          // if base object and current object has the key then 
         // check if the type is an object
         if(typeof curr[keys] ==='object'){
          // now get the key from both the object 
          // & check which one is missong. Add that key and value to the 
          // base object
           let keysFromACC = Object.keys(acc[keys]);
          let keysFromCURR = Object.keys(curr[keys]);
          keysFromCURR.forEach(function(item){
           if(keysFromACC.indexOf(item) ===-1){
              acc[keys][item] = curr[keys][item]
           }
          })
         }
      }
      else{
       // if the base object does not have key which current object
       // has then add the key to base object
       acc[keys]= curr[keys]
      }
    
    }
    return acc;

},list[0]);


console.log(x)

1 Comment

Note that this moves the problem of deep merging only one level deeper and works with the data provided but not for 3rd level nested objects like list[x].b.k.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.