Lodash 过滤器带有限制

3

有没有一种方法可以从匹配某个条件的数组中过滤出前n个元素?

我知道你可以使用filter然后调用take,但这不是遍历整个列表而不是在达到限制后退出吗?

_(books).filter(function(book) {return book.pages > 10}).take(5).value();

它遍历列表的问题是什么?如果您正在尝试从数千条记录中取出5条,应该在优化数组过滤之前尝试限制返回的数据量。或者,如果这很重要,可以包装自己的迭代器,并在满足条件时退出它。 - VtoCorleone
@VtoCorleone,你有包装自己的迭代器的示例吗? - NDavis
7个回答

3
如果传递给 _.forEach() 函数的迭代器函数返回 false,则立即停止迭代。
以下的 filter 函数说明了如何使用 _.forEach() 解决您的用例。

function filter(books, maxCount) {
  var results = [];
  _.forEach(books, function(book) {
    if (results.length === maxCount) {
      return false;
    }
    if (book.pages > 10) {
      results.push(book);
    }
  });
  return results;
}


var N = 5;
var books = new Array(20);

// Give each book a page count equal to its books index.
_.forEach(books, function(v, i) {books[i] = {pages: i}});

console.log(filter(books, N));
<script src="https://cdn.jsdelivr.net/lodash/4.15.0/lodash.min.js"></script>


0
据我所知,只有一个lodash函数允许您提前终止,那就是_.transform

result = _(books).transform(function(result, book) {
 book.pages > 10 && result.push(book);
 return result.length < 5;
}).value();

document.write(JSON.stringify(result));
<script src="https://cdn.rawgit.com/lodash/lodash/4.15.0/dist/lodash.min.js"></script>
<script>
  var books = [
    { title: 'a', pages: 8 },
    { title: 'b', pages: 10 },
    { title: 'c', pages: 12 },
    { title: 'd', pages: 14 },
    { title: 'e', pages: 16 },
    { title: 'f', pages: 5 },
    { title: 'g', pages: 18 },
    { title: 'h', pages: 20 }
  ]
</script>

当然,您也可以使用Mixin来创建自己的API:

// define mixin once somewhere:
_.mixin({'findWhile': function(collection, predicate, num) {
  return _.transform(collection, function(result, value) {
    predicate(value) && result.push(value);
    return result.length < num;
  });
}});

// then to use it:
var result = _(books).findWhile(function(book) { return book.pages > 10 }, 5).value();

document.write(JSON.stringify(result));
<script src="https://cdn.rawgit.com/lodash/lodash/4.15.0/dist/lodash.min.js"></script>
<script>
  var books = [
    { title: 'a', pages: 8 },
    { title: 'b', pages: 10 },
    { title: 'c', pages: 12 },
    { title: 'd', pages: 14 },
    { title: 'e', pages: 16 },
    { title: 'f', pages: 5 },
    { title: 'g', pages: 18 },
    { title: 'h', pages: 20 }
  ]
</script>


0
const length = 5;
_.slice(books, length + 1);

使用 ARRAY SLICE / LoDASH SLICE 可以轻松通过长度限制数组

这里的长度限制为5,你需要增加(+1),因为数组索引从零(0)开始


0

你的解决方案对于几乎所有情况都很好,除非你需要处理大量数据。我想不出更有效的 lodash 解决方案,但这个方案已经足够了:

var take = 5;
var result = [];

for(var i = 0; i < books.length; i++) {
  var book = books[i];
  if(book.pages > 10) {
    result.push(book);
    --take;
  }
  if(take === 0) {
    break;
  }
}

1
复制了你的减量模式,因为它更易读,可以知道要取多少+1 :) - naveen

0

另一种方式

var limit = 5,
    result = [];
_.forEach(books, function(book) {
    if (limit--) {
        return false;
    } else {
        if (book.pages > 10) {
            result.push(book);
        }
    }
});

你应该添加一个引用,说明你从哪个答案中“复制”了这个模式。此外,解释代码如何帮助用户几乎总是一个好主意。 - Heretic Monkey
不确定你在说什么。但是你在另一个答案的评论中已经说过,你复制了它。根据CC-by-SA许可证,你必须给予其他用户归属。但无论如何,哈哈。 - Heretic Monkey
我对 OP 很友好,我没有复制任何东西,请查看我的编辑历史。 - naveen

0
    book.pages.push(page);
    if(book.pages.length > WHATEVER){
        book.pages = _.drop(book.pages, book.pages.length - WHATEVER );
    }

-1

你可以直接设置数组的长度

var numbers = [1, 2, 3, 4, 5];

if (numbers.length > 3) {
    numbers.length = 3;
}

console.log(numbers); // [1, 2, 3]
console.log(numbers.length); // 3

请参阅MDN webdocs Array.length


OP正在寻找一种方法使filter()在达到限制后退出,以避免昂贵的性能成本。看起来你只是在展示如何在执行了那个昂贵的操作之后截断数组。 - Ian Dunn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接