【问题标题】:Lodash to filter out an array of objectsLodash 过滤出一组对象
【发布时间】:2019-09-26 16:33:46
【问题描述】:

我正在尝试使用 lodash 过滤出嵌套的对象数组,这非常简单,但我希望避免多次调用。

我希望使用单个 lodash 调用/函数创建 2 个对象数组。查找对象属性“$isMultiAccount”(如果存在)将整个对象放入一个结果集中,如果不将其放入另一个规则集。

目前我正在使用 Lodash “has and filter” 为第一个和其他“!has” 这意味着相同的对象循环两次,因为对象相对较大,它会造成速度瓶颈

https://repl.it/repls/HomelyExpensiveTruetype

const item = {
  "domains": [
    {
      "id": "dm11022",
      "information":{
        "description": "Customer",
        "owner": {
          "primary":{
            "name": "James",
            "phone": "NA"
          },
          "others": [
            {
              "$isMultiAccount": "./Yes"
            }
          ]
        }
      }
    },
    {
      "id": "dm12022",
      "information":{
        "description": "Customer",
        "owner": {
          "primary":{
            "name": "James",
            "phone": "NA"
          },
          "others": [
            {
              "$isMultiAccount": "./No"
            }
          ]
        }
      }
    },
    {
      "id": "dm12022",
      "information":{
        "description": "Customer",
        "owner": {
          "primary":{
            "name": "James",
            "phone": "NA"
          },
          "others": [
            {
              "conf": {
                  "isVpnBased":{
                    "accountType": "Primary"
                  }
              }
            }
          ]
        }
      }
    }


  ]
}
/*
Expected result
  output1 = [
        {
      "id": "dm11022",
      "information":{
        "description": "Customer",
        "owner": {
          "primary":{
            "name": "James",
            "phone": "NA"
          },
          "others": [
            {
              "$isMultiAccount": "./Yes"
            }
          ]
        }
      }
    },
    {
      "id": "dm12022",
      "information":{
        "description": "Customer",
        "owner": {
          "primary":{
            "name": "James",
            "phone": "NA"
          },
          "others": [
            {
              "$isMultiAccount": "./No"
            }
          ]
        }
      }
    }
  ]

// $isMultiAccount account do not exist in this object
 output2 = [
       {
      "id": "dm12022",
      "information":{
        "description": "Customer",
        "owner": {
          "primary":{
            "name": "James",
            "phone": "NA"
          },
          "others": [
            {
              "conf": {
                  "isVpnBased":{
                    "accountType": "Primary"
                  }
              }
            }
          ]
        }
      }
    }
 ]


 */

【问题讨论】:

  • 并不是说这在这种情况下一定适用,但有时在使用lodash甚至构建ES5数组方法时,如果出现本质上循环两次的情况,有时您需要使用单个传统循环(或者更好,有时reduce

标签: javascript arrays ecmascript-6 lodash


【解决方案1】:
const item = {
"domains": [
{
  "id": "dm11022",
  "information":{
    "description": "Customer",
    "owner": {
      "primary":{
        "name": "James",
        "phone": "NA"
      },
      "others": [
        {
          "$isMultiAccount": "./Yes"
        }
      ]
    }
  }
},
{
  "id": "dm12022",
  "information":{
    "description": "Customer",
    "owner": {
      "primary":{
        "name": "James",
        "phone": "NA"
      },
      "others": [
        {
          "$isMultiAccount": "./No"
        }
      ]
    }
  }
},
{
  "id": "dm12022",
  "information":{
    "description": "Customer",
    "owner": {
      "primary":{
        "name": "James",
        "phone": "NA"
      },
      "others": [
        {
          "conf": {
              "isVpnBased":{
                "accountType": "Primary"
              }
          }
        }
      ]
    }
  }
}
]
}
const [areMulti, areNotMulti] = _.reduce(item.domains, (current, next) => {
  return _.has(next, ‘information.owner.others.$isMultiAccount’)
    ? [current[0].concat(next), current[1]]
    : [current[0], current[1].concat(next)];
}, [[], []]);
console.log(areMulti);
console.log(areNotMulti);

【讨论】:

    【解决方案2】:

    由于 item.domains.information.owner.others 是一个数组,所以需要按如下方式处理:

    let multi = []; 
    let notMulti = [];
    _.each(item.domains, function (obj) {
       if (obj.information.owner.others.length && _.has(obj.information.owner.others[0], '$isMultiAccount'))
          multi.push(obj);
       else
          notMulti.push(obj);
    });
    console.log(multi);
    console.log(notMulti);
    

    【讨论】:

      【解决方案3】:

      不幸的是,您必须遍历 domains 数组以及 owner.others 数组以确定具有特定键的对象是否位于其中。

      所以该算法具有O(n*m) 复杂度。

      如果您要求 lodash 函数,似乎 partition 方法就是您正在寻找的

      正如文档所说:

      创建一个元素数组,分成两组,第一组包含元素谓词返回真值,第二组包含元素谓词返回假值。谓词使用一个参数调用:(值)。

      所以它会是这样的:

      _.partition(
        item.domains,
        e => _.some(
          _.get(e, 'information.owner.others'),
          el => _.has(el,"$isMultiAccount")
        )
      );
      

      当心 - 一些黑客可用!

      但是,如果您 100% 确定您要查找的元素将始终位于特定索引处(例如,它应该始终作为第一个元素 - 所以索引为 0),您可以将算法限制为O(n) 具有线性复杂度,因为只有 domains 数组的大小对性能有影响。

      假设固定数组索引 = 0 的 hackish 解决方案:

      _.partition(
        item.domains,
        e => _.has(e, 'information.owner.others.0.$isMultiAccount')
      );
      

      注意 使用 lodash 使代码更易于阅读,但当然它无论如何都会产生一些性能开销。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-22
        • 2022-01-18
        • 2023-01-25
        • 2018-09-06
        • 2017-12-22
        • 2015-07-10
        • 2016-03-23
        • 1970-01-01
        相关资源
        最近更新 更多