映射具有未知键或长度的对象数组
Mapping Array Of Objects with Unknown Keys or Lengths
我有一些数据要输出到 Excel。我的正常功能与“正常”数据正常工作给我带来了问题,具体来说,我在我的 MappedArrays
变量中看到返回数组的 undefined
并且似乎丢失了一行数据。
我试图简化问题以制作 MCVE,这甚至可能不是问题,但我希望我的主要功能能够正确处理它。
假设我有一堆键数未知的对象,并不是每个对象都有每个键。
我目前有一个函数来确保每个对象都有每个键(这是将数据粘贴到excel中所需要的,值可以是null
)。
我有另一个函数可以将对象数组转换为映射数组数组,其中所有值都应按索引定位。
在我的测试数据中,我在一个对象中有一个 "Header_E": "Test",
行,当前正在输出它看起来是对象中的索引,它应该与 [的索引相关联=39=].
Header_A Header_B Header_C Header_D Header_E Header_F
2AVal 2BVal
3AVal 3BVal
4AVal 4BVal 4DVal
Test
如何确保对象数组中的所有对象都具有所有键,然后将 ArrOfObjs 映射到一个数组,并将数据索引到对象键
这是我的示例数据:
async function CommandsFunc(event) {
try {
await Excel.run(async (context) => {
//Start Func.
var ws = context.workbook.worksheets.getActiveWorksheet();
var Obj_One_A = {
"Header_A": "2AVal",
"Header_B": "2BVal",
}
var Obj_Two_A = {
"Header_A": "3AVal",
"Header_B": "3BVal",
}
var Obj_One_B = {
"Header_A": "4AVal",
"Header_B": "4BVal",
"Header_D": "4DVal",
}
var Obj_Two_B = {
"Header_A": "",
"Header_C": "",
"Header_E": "Test",
"Header_F": "",
}
var Arr_Of_Items = [Obj_One_A, Obj_Two_A]
//await Do_Arr_Of_Objs_Or_Arrs_To_Rng(context, ws, Arr_Of_Items)
var HeaderArr = ["Header_A", "Header_B"]
var MappedArrays = await Get_Mapped_Over_Array_Of_Objects(Arr_Of_Items, HeaderArr)
MappedArrays.unshift(HeaderArr)
var rng = ws.getRangeByIndexes(0, 0, MappedArrays.length, MappedArrays[0].length)
rng.select()
await context.sync();
rng.values = MappedArrays
await context.sync();
var Arr_Of_Items = [Obj_One_B, Obj_Two_B]
var All_Headers_Arr = ["Header_A", "Header_B", "Header_C", "Header_D", "Header_E", "Header_F"]
var MappedArrays = await Get_Mapped_Over_Array_Of_Objects(Arr_Of_Items, All_Headers_Arr)
var Used_Rng = ws.getUsedRange(true)
Used_Rng.load('rowCount')
await context.sync()
var rng = ws.getRangeByIndexes(Used_Rng.rowCount, 0, MappedArrays.length, All_Headers_Arr.length)
//Set Headers
for (let ai = 0; ai < All_Headers_Arr.length; ai++) {
ws.getUsedRange(true).getRow(0).getCell(0, ai).values = All_Headers_Arr[ai]
}
rng.select()
await context.sync();
rng.values = MappedArrays
await context.sync();
//await Do_Arr_Of_Objs_Or_Arrs_To_Rng(context, ws, Arr_Of_Items)
//End Func
await context.sync();
});
} catch (error) {
console.log(error)
}
try { event.completed() } catch (error) { }
}
辅助函数:
async function Get_Mapped_Over_Array_Of_Objects(ArrayOfObjs, MapArr) {
ArrayOfObjs = await Do_All_Arr_Of_Objs_Same_Keys(ArrayOfObjs, MapArr)
let MappedArrays = []
for (let i = 0; i < ArrayOfObjs.length; i++) {
var obj = ArrayOfObjs[i]
var arr = Object.keys(obj).map((k) => obj[k])
MappedArrays.push(arr)
}
return MappedArrays;
}
async function Do_All_Arr_Of_Objs_Same_Keys(Arr_Of_Objs, Keys_Arr) {
for (let oi = 0; oi < Arr_Of_Objs.length; oi++) {
var obj = Arr_Of_Objs[oi]
var Obj_Keys = Object.keys(obj)
if (Keys_Arr.length != Obj_Keys.length) {
var temp_arr = []
temp_arr = Keys_Arr
for (let ki = 0; ki < Obj_Keys.length; ki++) {
temp_arr = await Do_Remove_Arr_By_Val(temp_arr, Obj_Keys[ki])
}
for (let ai = 0; ai < temp_arr.length; ai++) {
obj[temp_arr[ai]] = ""
}
}
}
return Arr_Of_Objs
}
function Do_Remove_Arr_By_Val(arr, val) {
var filteredArray = arr.filter(function (e) { return e !== val })
return filteredArray
}
您的问题是由这一行引起的:
var arr = Object.keys(obj).map((k) => obj[k])
这是按照键在对象中定义的顺序将值推入 arr
,每个对象不一定相同。您会注意到,在示例输出的第三行中,Header_C
列中有 Header_D
的值,这是同一问题的表现。
由于您知道每个对象在执行此函数时都具有相同的键集,因此您应该迭代该常量键列表 (All_Headers_Arr
) 而不是 Object.keys(obj)
。这将确保 arr
的所有值都被一致地索引。
话虽如此,我认为还可以按照此代码段的方式简化您的代码。
var Obj_One_A = { "Header_A": "2AVal", "Header_B": "2BVal" }
var Obj_Two_A = { "Header_A": "3AVal", "Header_B": "3BVal" }
var Obj_One_B = { "Header_A": "4AVal", "Header_B": "4BVal", "Header_D": "4DVal" }
var Obj_Two_B = { "Header_A": "", "Header_C": "", "Header_E": "Test", "Header_F": "" }
var Arr_Of_Items = [Obj_One_A, Obj_Two_A, Obj_One_B, Obj_Two_B]
// get a list of unique headers
let Headers = new Set()
Arr_Of_Items
.forEach(o => Object.keys(o)
.forEach(k => Headers.add(k))
)
// convert to an array
All_Headers = Array.from(Headers.values()).sort()
// make sure each object has all the headers, assigning null values to any missing headers
const MappedArrays = Arr_Of_Items
.map(o => All_Headers
.map(h => o.hasOwnProperty(h) ? o[h] : null)
)
console.log(MappedArrays)
我有一些数据要输出到 Excel。我的正常功能与“正常”数据正常工作给我带来了问题,具体来说,我在我的 MappedArrays
变量中看到返回数组的 undefined
并且似乎丢失了一行数据。
我试图简化问题以制作 MCVE,这甚至可能不是问题,但我希望我的主要功能能够正确处理它。
假设我有一堆键数未知的对象,并不是每个对象都有每个键。
我目前有一个函数来确保每个对象都有每个键(这是将数据粘贴到excel中所需要的,值可以是null
)。
我有另一个函数可以将对象数组转换为映射数组数组,其中所有值都应按索引定位。
在我的测试数据中,我在一个对象中有一个 "Header_E": "Test",
行,当前正在输出它看起来是对象中的索引,它应该与 [的索引相关联=39=].
Header_A Header_B Header_C Header_D Header_E Header_F
2AVal 2BVal
3AVal 3BVal
4AVal 4BVal 4DVal
Test
如何确保对象数组中的所有对象都具有所有键,然后将 ArrOfObjs 映射到一个数组,并将数据索引到对象键
这是我的示例数据:
async function CommandsFunc(event) {
try {
await Excel.run(async (context) => {
//Start Func.
var ws = context.workbook.worksheets.getActiveWorksheet();
var Obj_One_A = {
"Header_A": "2AVal",
"Header_B": "2BVal",
}
var Obj_Two_A = {
"Header_A": "3AVal",
"Header_B": "3BVal",
}
var Obj_One_B = {
"Header_A": "4AVal",
"Header_B": "4BVal",
"Header_D": "4DVal",
}
var Obj_Two_B = {
"Header_A": "",
"Header_C": "",
"Header_E": "Test",
"Header_F": "",
}
var Arr_Of_Items = [Obj_One_A, Obj_Two_A]
//await Do_Arr_Of_Objs_Or_Arrs_To_Rng(context, ws, Arr_Of_Items)
var HeaderArr = ["Header_A", "Header_B"]
var MappedArrays = await Get_Mapped_Over_Array_Of_Objects(Arr_Of_Items, HeaderArr)
MappedArrays.unshift(HeaderArr)
var rng = ws.getRangeByIndexes(0, 0, MappedArrays.length, MappedArrays[0].length)
rng.select()
await context.sync();
rng.values = MappedArrays
await context.sync();
var Arr_Of_Items = [Obj_One_B, Obj_Two_B]
var All_Headers_Arr = ["Header_A", "Header_B", "Header_C", "Header_D", "Header_E", "Header_F"]
var MappedArrays = await Get_Mapped_Over_Array_Of_Objects(Arr_Of_Items, All_Headers_Arr)
var Used_Rng = ws.getUsedRange(true)
Used_Rng.load('rowCount')
await context.sync()
var rng = ws.getRangeByIndexes(Used_Rng.rowCount, 0, MappedArrays.length, All_Headers_Arr.length)
//Set Headers
for (let ai = 0; ai < All_Headers_Arr.length; ai++) {
ws.getUsedRange(true).getRow(0).getCell(0, ai).values = All_Headers_Arr[ai]
}
rng.select()
await context.sync();
rng.values = MappedArrays
await context.sync();
//await Do_Arr_Of_Objs_Or_Arrs_To_Rng(context, ws, Arr_Of_Items)
//End Func
await context.sync();
});
} catch (error) {
console.log(error)
}
try { event.completed() } catch (error) { }
}
辅助函数:
async function Get_Mapped_Over_Array_Of_Objects(ArrayOfObjs, MapArr) {
ArrayOfObjs = await Do_All_Arr_Of_Objs_Same_Keys(ArrayOfObjs, MapArr)
let MappedArrays = []
for (let i = 0; i < ArrayOfObjs.length; i++) {
var obj = ArrayOfObjs[i]
var arr = Object.keys(obj).map((k) => obj[k])
MappedArrays.push(arr)
}
return MappedArrays;
}
async function Do_All_Arr_Of_Objs_Same_Keys(Arr_Of_Objs, Keys_Arr) {
for (let oi = 0; oi < Arr_Of_Objs.length; oi++) {
var obj = Arr_Of_Objs[oi]
var Obj_Keys = Object.keys(obj)
if (Keys_Arr.length != Obj_Keys.length) {
var temp_arr = []
temp_arr = Keys_Arr
for (let ki = 0; ki < Obj_Keys.length; ki++) {
temp_arr = await Do_Remove_Arr_By_Val(temp_arr, Obj_Keys[ki])
}
for (let ai = 0; ai < temp_arr.length; ai++) {
obj[temp_arr[ai]] = ""
}
}
}
return Arr_Of_Objs
}
function Do_Remove_Arr_By_Val(arr, val) {
var filteredArray = arr.filter(function (e) { return e !== val })
return filteredArray
}
您的问题是由这一行引起的:
var arr = Object.keys(obj).map((k) => obj[k])
这是按照键在对象中定义的顺序将值推入 arr
,每个对象不一定相同。您会注意到,在示例输出的第三行中,Header_C
列中有 Header_D
的值,这是同一问题的表现。
由于您知道每个对象在执行此函数时都具有相同的键集,因此您应该迭代该常量键列表 (All_Headers_Arr
) 而不是 Object.keys(obj)
。这将确保 arr
的所有值都被一致地索引。
话虽如此,我认为还可以按照此代码段的方式简化您的代码。
var Obj_One_A = { "Header_A": "2AVal", "Header_B": "2BVal" }
var Obj_Two_A = { "Header_A": "3AVal", "Header_B": "3BVal" }
var Obj_One_B = { "Header_A": "4AVal", "Header_B": "4BVal", "Header_D": "4DVal" }
var Obj_Two_B = { "Header_A": "", "Header_C": "", "Header_E": "Test", "Header_F": "" }
var Arr_Of_Items = [Obj_One_A, Obj_Two_A, Obj_One_B, Obj_Two_B]
// get a list of unique headers
let Headers = new Set()
Arr_Of_Items
.forEach(o => Object.keys(o)
.forEach(k => Headers.add(k))
)
// convert to an array
All_Headers = Array.from(Headers.values()).sort()
// make sure each object has all the headers, assigning null values to any missing headers
const MappedArrays = Arr_Of_Items
.map(o => All_Headers
.map(h => o.hasOwnProperty(h) ? o[h] : null)
)
console.log(MappedArrays)