最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to fill in missing keys in an Array of Objects? - Stack Overflow

programmeradmin0浏览0评论

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)

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)

Share Improve this question asked Dec 18, 2017 at 14:47 WoJWoJ 30.1k58 gold badges214 silver badges405 bronze badges 7
  • 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. – T.J. Crowder Commented Dec 18, 2017 at 14:49
  • You really don't know the keys in advance? – T.J. Crowder Commented Dec 18, 2017 at 14:49
  • 1 Your approach in this case seems OK, but you might consider using a set instead of an array for allkeys. The value of allkeys in your code ends up being [ "a", "b", "c", "a", "c", "b", "c" ], but should really be ["a", "b", "c"]. – Cristian Lupascu Commented Dec 18, 2017 at 14:51
  • @T.J.Crowder: no, I get the data from an otherwise unhelpful API so I will have the case of non-existing keys only (not ones which have the value undefined) – WoJ Commented Dec 18, 2017 at 14:53
  • @GolfWolf: thanks - I e from the Python world where I would have used exactlky that (a set), glad to see that there is the same in JS – WoJ Commented Dec 18, 2017 at 14:54
 |  Show 2 more ments

3 Answers 3

Reset to default 6

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

https://developer.mozilla/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);

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)...

You can use Object.assign to merge each element with an object holding default key-values:

var arr = [{
    "a": 1,
    "b": 2,
    "c": 3
  },
  {
    "a": 10,
    "c": 30
  },
  {
    "b": 200,
    "c": 300
  },
];
var defaultObj = arr.reduce((m, o) => (Object.keys(o).forEach(key => m[key] = 0), m), {});
arr = arr.map(e => Object.assign({}, defaultObj, e));
console.log(arr);

发布评论

评论列表(0)

  1. 暂无评论