【问题标题】:JS: Lodash partition by a array of predicatesJS:Lodash 通过谓词数组进行分区
【发布时间】:2018-08-19 10:52:31
【问题描述】:

我得到以下为我工作。只是好奇是否有“更好”的方法。

var users = [
  { 'user': 'barney',  'age': 36, 'active': false },
  { 'user': 'fred',    'age': 40, 'active': true },
  { 'user': 'pebbles', 'age': 1,  'active': false }
];
 
_.partition(users, ({user}) => {
   if (_.includes(['fred', 'pebbles'], user)) {
      return true
   } else {
     return false
   }
})

不知道该解决方案对于大量用户的可扩展性如何?

【问题讨论】:

  • 为什么不_.includes(['fred', 'pebbles'], user)
  • 很好,谢谢你的提示

标签: javascript ecmascript-6 lodash


【解决方案1】:

对我来说这是一个有趣的问题。我已经准备了一些测量的代码。也许这会帮助您做出正确的决定。

关于您的问题,我相信如果您需要最大性能,那么您必须使用最少的复杂代码。 Lodash 是一个很棒的工具,它使代码更具可读性,但是当您需要性能时,它不是一个选择。

(function() {
    const users = [
      { 'user': 'barney',  'age': 36, 'active': false },
      { 'user': 'fred',    'age': 40, 'active': true },
      { 'user': 'pebbles', 'age': 1,  'active': false }
    ];

    function function1 (queryArray) {
      return _.partition(users, ({user}) => _.includes(queryArray, user));
    }
    function function2 (queryArray) {
        const _output = [[], []];
        users.reduce((output, user) => {
            if(queryArray.indexOf(user.user) > -1) output[0].push(user);
            else output[1].push(user);
            return output;
        }, _output);
        return _output;
    }
    function function3 (queryArray) {
        const output = [[], []];
        for(let i = 0; i < users.length; i++){
            const user = users[i];
            if(queryArray.indexOf(user.user) > -1) output[0].push(user);
            else output[1].push(user);
        }
        return output;
    }


    const iterations = 1000000;
    const queryArray = ['fred', 'pebbles'];

    console.time('Function #1');
    for(let i = 0; i < iterations; i++ ){
        function1(queryArray);
    }
    console.timeEnd('Function #1');

    console.time('Function #2');
    for(let i = 0; i < iterations; i++ ){
        function2(queryArray);
    }
    console.timeEnd('Function #2');

    console.time('Function #3');
    for(let i = 0; i < iterations; i++ ){
        function3(queryArray);
    }
    console.timeEnd('Function #3');
})();
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"&gt;&lt;/script&gt;

这是我机器上的结果。您的浏览器中可能有其他结果,但比例大致相同。平均而言,lodash 解决方案需要大约两倍的时间。

Function #1: 787.700ms
Function #2: 466.300ms
Function #3: 275.900ms

【讨论】:

  • 您应该将 ['fred', 'pebbles'] 作为参数来消除基准测试中构建数组的成本。
  • @AKX 你是绝对正确的,但我的目标不是创建一个最佳解决方案。所有功能都应该在类似的条件下工作。无论如何,我已经更新了它。谢谢。
【解决方案2】:

首先,请注意if (someBoolean) { return true; } else { return false; } 完全等同于return someBoolean。所以你的代码可能会被简化:

const [fredOrPebblesUsers, otherUsers] = 
  _.partition(users, ({user}) => _.includes(['fred', 'pebbles'], user));

现在,它的可扩展性如何?好吧,您已经在内存中拥有完整的 users 数组,您只需再创建两个数组,其中包含对这些对象的引用(而不是值本身)。如果您一次需要全部或像lazy.js 这样的惰性库会有所帮助,那么了解您将如何使用这些分区值将是相关的。

在速度方面,@Max Martynov 已经讨论了 for 循环相对于箭头函数的增益。 IMO,只有当您看到这是您应用程序中的瓶颈时,您才应该使用箭头函数更改一个不错的抽象来实现笨重的 for 循环。

_.includes(['fred', 'pebbles'], 用户)

只比较两个值?如果你的真实代码有更多的值,你应该使用 Set 来进行 O(1) 比较而不是 O(n)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-05
    • 1970-01-01
    • 2012-01-04
    相关资源
    最近更新 更多