为了账号安全,请及时绑定邮箱和手机立即绑定

简化的 javascript for 循环

简化的 javascript for 循环

当年话下 2021-12-23 15:35:58
我有几个级别深的 javscript 对象。所有级别都是对象,除了最终级别是我需要排序的数组。到目前为止,我的代码如下所示:for (let group in objRes) {    if (objRes.hasOwnProperty(group)) {        for (let type in objRes[group]) {            if (objRes[group].hasOwnProperty(type)) {                for (let name in objRes[group][type]) {                    if (objRes[group][type].hasOwnProperty(name)) {                        for (let tenor in objRes[group][type][name]) {                            if (objRes[group][type][name].hasOwnProperty(tenor)) {                                objRes[group][type][name][tenor] = objRes[group][type][name][tenor].sort((x,y)=>x.date>y.date);                            }                        }                    }                }            }        }    }}级别 ( group, type, name, tenor) 都是字符串,最后一级数组成员如下所示:{date:'2019-12-25',value:35}所以objRes看起来像{group1:    {type1:        {name1:            {tenor1:[{date:'2019-12-25',value:35},...],         name2 :{...}         }    },    {type2 :{...}},group2:{...}}有没有聪明的方法来简化这个?您可以假设级别数已知或未知。
查看完整描述

2 回答

?
潇湘沐

TA贡献1816条经验 获得超6个赞

您可以为此使用递归函数。很难根据问题中的信息给出一个确切的例子,但例如:


function process(obj) {

    // Loop through the values of the own properties of the object

    for (const value of Object.values(obj)) {

        // Is this the termination condition?

        if (Array.isArray(value)) { // <== A guess at the condition, adjust as needed

            // We've reached the bottom

            value.sort((x, y) => x.date.localeCompare(y.date)); // <== Note correction, you can't just return the result of `>`

        } else {

            // Not the termination, recurse

            process(value);

        }

    }

}

使用猜测数据的实时示例:

function process(obj) {

    // Loop through the values of the own properties of the object

    for (const value of Object.values(obj)) {

        // Is this the termination condition?

        if (Array.isArray(value)) { // <== A guess at the condition, adjust as needed

            // We've reached the bottom

            value.sort((x, y) => x.date.localeCompare(y.date)); // <== Note correction, you can't just return the result of `>`

        } else {

            // Not the termination, recurse

            process(value);

        }

    }

}


const objRes = {

    group1: {

        type1: {

            name1: {

                tenor1: [

                    {date: '2019-12-23', value: 35},

                    {date: '2019-12-25', value: 32},

                    {date: '2019-12-24', value: 30},

                ]

            },

            name2 :[]

        },

        type2: {}

    },

    group2: {}

};

process(objRes);

console.log(JSON.stringify(objRes, null, 4));

.as-console-wrapper {

    max-height: 100% !important;

}

一些注意事项:

  1. 您可以通过使用来避免for-in/hasOwnProperty组合Object.values

  2. 您可以使用 遍历这些值for-of

  3. 必须有一些终止条件告诉函数何时到达“底部”。在那个例子中,我使用了Array.isArray因为你在最后一级排序。

  4. Array.prototype.sort 直接修改数组,不需要使用它的返回值。

  5. 您传递给的函数sort必须返回负数、0 或正数,而不是布尔值(更多信息请点击此处)。由于您的date值在yyyy-MM-dd形式上似乎是字符串,因此您可以使用localeCompare它(因为在这种格式中,字典比较也是日期比较)。


查看完整回答
反对 回复 2021-12-23
?
叮当猫咪

TA贡献1776条经验 获得超12个赞

这个替代 TJ Crowder 的答案采用了那里提到的几个决策点,并使它们显式函数调用。


const process = (test, transform, data) =>

  typeof data == "object"

    ? ( Array .isArray (data)

       ? (xs) => xs .map (([_, x]) => x)

       : Object .fromEntries

      ) ( Object .entries (data) .map (([k, v]) => 

        [k, test (k, v) ? transform (v) : process (test, transform, v)]

      ))

    : data  

它接受两个函数以及您的数据对象。第一个是测试您是否遇到了要按摩的嵌套值。所以我们可以想象像(k, v) => k .startsWith ('tenor')或 之类的东西(k, v) => Array .isArray (v)。第二个函数接受该条目处的值并返回一个更新的值,可能是(v) => v . sort((a, b) => a .date .localeCompare (b .date))。


(注意:您的排序调用是有问题的。不要使用.sort ((a, b) => a < b),它返回一个布尔值,然后被强制转换为 a0或 a 1,而适当的比较器应该返回-1when a < b。如果您可以与 进行比较<,那么这应该始终有效(a, b) =>  a < b ? -1 : a > b ? 1 : 0。我不”不知道是否有比使用 .sort((a,b) => a>b) 对数组进行排序更完整的问题。为什么?。)


您可以在此代码段中看到它的运行情况:

const process = (test, transform, data) =>

  typeof data == "object"

    ? ( Array .isArray (data)

        ? (xs) => xs .map (([_, x]) => x)

        : Object .fromEntries

      ) ( Object .entries (data) .map (([k, v]) => 

        [k, test (k, v) ? transform (v) : process (test, transform, v)]

      ))

    : data    


const dateSort = (xs) => xs .slice (0) .sort ((a, b) => a .date .localeCompare (b .date))


const objRes = {

    group1: {

        type1: {

            name1: {

                tenor1: [

                    {date: '2019-12-23', value: 35},

                    {date: '2019-12-25', value: 32},

                    {date: '2019-12-24', value: 30},

                ]

            },

            name2: []

        },

        type2: {}

    },

    group2: {

        type3: [

            {date: '2020-01-03', value: 42},

            {date: '2019-01-01', value: 43},

            {date: '2019-01-02', value: 44},

        ]

    }

};


// This one only sorts the first group of dates

console .log (

  process (

    (k, v) => k .startsWith ('tenor'),

    dateSort,

    objRes

  )

)


// This one sorts both groups

console .log (

  process (

    (k, v) => Array .isArray (v),

    dateSort,

    objRes

  )

)

代码有点密集。最外层条件仅在数据是对象时才应用我们的处理,如果不是则完整返回,如果是则执行以下处理:


我们首先使用Object.entries将我们的对象转换为名称-值对,然后通过测试每一对来映射该对象,看看我们是否遇到了应该转换的东西,并返回转换后的值或对值进行递归的结果。


也许最棘手的一点是:


      ( Array .isArray (data)

        ? (xs) => xs .map (([_, x]) => x)

        : Object .fromEntries

      )

在这里,我们只选择一个函数应用到转换后的对上,将其重新变成一个整体。如果它是一个数组,我们跳过键并返回一个值数组。如果不是,我们就用它们Object.fromEntries来创建一个对象。如果Object.entries是不是在你的环境中使用,很容易垫片。


查看完整回答
反对 回复 2021-12-23
  • 2 回答
  • 0 关注
  • 163 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信