Merge Unknown number of objects in array into single js object

Viewed 55

I have an object as follows

[
    {
        "config": {
            "holes": 18
        }
    },
    {
        "config": {
            "single_cart": false
        }
    },
    {
        "config": {
            "shared_cart": false
        }
    },
    {
        "config": {
            "caddie": false
        }
    },
    {
        "config": {
            "transfers": false
        }
    },
    {
        "config": {
            "meals": false
        }
    },
    {
        "config": {
            "all_inclusive": false
        }
    }
]

which i am trying to convert into

{
   "config":{
      "holes":18,
      "single_cart":false,
      "shared_cart":false,
      "caddie":false,
      "transfers":false,
      "meals":false,
      "all_inclusive":false
   }
}

This is an example 'merge' as these could be of any name and value key. I have tried and failed to use reduce, map, foreach and can never join them together as such.

If someone can help point me in the right direction that would be amazing. All the examples i have seen refer to specifically named keys to do the merge using object.assign etc..

5 Answers

You can use reduce() to merge all the objects in the array. You can use ... spread syntax to combine objects.

const data = [{
    "config": {
      "holes": 18
    }
  },
  {
    "config": {
      "single_cart": false
    }
  },
  {
    "config": {
      "shared_cart": false
    }
  },
  {
    "config": {
      "caddie": false
    }
  },
  {
    "config": {
      "transfers": false
    }
  },
  {
    "config": {
      "meals": false
    }
  },
  {
    "config": {
      "all_inclusive": false
    }
  }
];

const result = {
  config: data.reduce((acc, obj) => ({...acc, ...obj.config}), {})
};

console.log(result);

That should be a one-liner:

let data = [ 
    {
        "config": {
            "holes": 18
        }
    },
    {
        "config": {
            "single_cart": false
        }
    },
    /* more of your data.... */ 
]

const result = data.reduce((prev, {config}) => ({config: {...prev.config, ...config}}), {config: {}})

You can reduce to flatten arrays or to create objects. You don't even need to declare a separate variable to assign your data to.

If you have a default config or previous data, you want to override, you can change the second parameter of the reduce function:


const defaultConfig = {
    config: {
      "holes": 0,
      "single_cart": true,
    }
}

const newConfig = data.reduce((prev, {config}) => ({config: {...prev.config, ...config}}), defaultConfig)

See more in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

I created a codepen here

which does what you were looking for in a fairly simple way.

const data = [
    {
        "config": {
            "holes": 18
        }
    },
    {
        "config": {
            "single_cart": false
        }
    },
    {
        "config": {
            "shared_cart": false
        }
    },
    {
        "config": {
            "caddie": false
        }
    },
    {
        "config": {
            "transfers": false
        }
    },
    {
        "config": {
            "meals": false
        }
    },
    {
        "config": {
            "all_inclusive": false
        }
    }
]

const obj = { 
  config: {} 
}

data.forEach((row) => {
  obj.config[Object.keys(row.config)[0]] = row.config[Object.keys(row.config)[0]];
})

console.log(obj);

Here is a way to do it without knowing any of the keys in advance.

const input = [
  {
    "config": {
      "holes": 18
    }
  },
  {
    "config": {
      "single_cart": false
    }
  },
  {
    "config": {
      "shared_cart": false
    }
  },
  {
    "config": {
      "caddie": false
    }
  },
  {
    "config": {
      "transfers": false
    }
  },
  {
    "config": {
      "meals": false
    }
  },
  {
    "config": {
      "all_inclusive": false
    }
  }
];

const mergeObjects = (a, b) => {
  for (let k in b) {
    if (k in a) {
      if (typeof(a[k]) === 'object' && typeof(b[k]) === 'object') {
        a[k] = mergeObjects(a[k], b[k]);
      } else {
        throw `Unable to merge because key "${k}" is in both objects (and not both values are objects).`;
      }
    } else {
      a[k] = b[k];
    }
  }

  return a;
};

const output = input.reduce(mergeObjects, {});

console.log(output);

I'm going to assume your list is called configList. This should work:

const result = { config: {} }

configList.forEach(element => {
   let key = Object.keys(element.config)
   let value = element.config[key]
   
   result.config[key] = value
})

console.log(result)
   
Related