Как заполнить недостающие ключи в массиве объектов?

У меня есть массив объектов, которые должны иметь одинаковые ключи, но некоторые из них отсутствуют. Я хотел бы заполнить недостающие ключи общим значением.

Я ищу простой способ сделать это (изначально или через библиотеку), код ниже, который я использую сейчас, работает, немного смотрит на мои необученные глаза довольно тяжелые, и я уверен, что заново изобрел утомительный способ сделать что-то, пока есть простой один.

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)
3 ответа

Вот версия, использующая свойство spread в объектных литералах, хотя это будет иметь очень ограниченную поддержку браузера:

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


Ваша версия в порядке, хотя я, вероятно, избежу всех этих concat вызовов массива, просто concat объект (или Set) с помощью клавиш. Это также немного менее неудобно 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: обратите внимание, что существует разница между существующим и undefined значением, а также свойство, которое вообще не существует. Ваш код обрабатывает их как одно и то же. Конечно, если вы знаете, что они не будут иметь undefined значение (например, из-за API, из которого вы их получите)...


Вы можете использовать Object.assign для объединения каждого элемента с объектом, имеющим значения ключа по умолчанию:

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

licensed under cc by-sa 3.0 with attribution.