映射具有未知键或长度的对象数组

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)