Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fill in missing keys in an Array of Objects?

Tags:

javascript

I have an Array of Objects which should all have the same keys, but some of the keys are missing. I would like to fill in the missing keys with a generic value.

I am looking for a simple way to do that (natively or via a library), the code below I use now works, bit looks to my untrained eyes quite heavy and I am sure I reinvented the tedious way to do something while there is a simple one.

var arr = [{
    "a": 1,
    "b": 2,
    "c": 3
  },
  {
    "a": 10,
    "c": 30
  },
  {
    "b": 200,
    "c": 300
  },
]
// get the list of all keys
var allkeys = []
arr.forEach((objInArr) => {
  allkeys = allkeys.concat(Object.keys(objInArr))
})
// check all arr entries for missing keys
arr.forEach((objInArr, i) => {
  allkeys.forEach((key) => {
    if (objInArr[key] === undefined) {
      // the generic value, in this case 0
      arr[i][key] = 0
    }
  })
})
console.log(arr)
like image 576
WoJ Avatar asked Oct 24 '25 17:10

WoJ


2 Answers

Here is a version using property spread in object literals, although this will have very limited browser support:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator

var arr = [{
    "a": 1,
    "b": 2,
    "c": 3
  },
  {
    "a": 10,
    "c": 30
  },
  {
    "b": 200,
    "c": 300
  },
]

// Create an object with all the keys in it
// This will return one object containing all keys the items
let obj = arr.reduce((res, item) => ({...res, ...item}));

// Get those keys as an array
let keys = Object.keys(obj);

// Create an object with all keys set to the default value (0)
let def = keys.reduce((result, key) => {
  result[key] = 0
  return result;
}, {});

// Use object destrucuring to replace all default values with the ones we have
let result = arr.map((item) => ({...def, ...item}));

// Log result
console.log(result);
like image 62
user184994 Avatar answered Oct 26 '25 05:10

user184994


Your version is fine, although I would probably avoid all those array concat calls by just building up an object (or Set) with the keys. It's also a bit less clunky with for-of:

var arr = [{
    "a": 1,
    "b": 2,
    "c": 3
  },
  {
    "a": 10,
    "c": 30
  },
  {
    "b": 200,
    "c": 300
  },
];
// Get all the keys
const keyObj = Object.create(null);
for (const entry of arr) {
  for (const key of Object.keys(entry)) {
    keyObj[key] = true;
  }
}
const allkeys = Object.keys(keyObj);
// Check all arr entries for missing keys
for (const entry of arr) {
  for (const key of allkeys) {
    if (entry[key] === undefined) { // ***I'd change this
      entry[key] = 0;
    }
  }
}
console.log(arr);
.as-console-wrapper {
  max-height: 100% !important;
}

Re *** I'd change this: Note that there's a difference between a property that exists and has the value undefined and a property that doesn't exist at all. Your code is treating them as the same thing. Of course, if you know they won't have the value undefined (for instance, because of the API you're getting them from)...

like image 37
T.J. Crowder Avatar answered Oct 26 '25 07:10

T.J. Crowder



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!