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

条件过滤,断路取n

条件过滤,断路取n

蛊毒传说 2021-12-02 14:38:34
按条件过滤并在具有断路的阵列中取前 n 个结果的最佳方法是什么?在预定义的项目列表上考虑搜索过滤器:[1, 2, 3, 4, 5, 6].filter(x => {  console.log(x);  return x < 4;}).take(2) === [1, 2];// 1// 2// true该take函数不存在,因为过滤器函数只返回一个数组,我想要流的断路功能。是否有使用功能方法的组合会产生这种情况?IE// would not process 3, 4, 5, or 6 as the circuit would break at 2.take([1, 2, 3, 4, 5, 6], x => x < 4, 2) === [1, 2]如果没有更多元素,该功能也应该停止。IEtake([1, 2, 3], x => x < 4, 4) === [1, 2, 3]
查看完整描述

3 回答

?
精慕HU

TA贡献1845条经验 获得超8个赞

For 循环很聪明,因为它们可以完成它们的工作,它们只是老了,所以从所有像我这样的时髦函数式程序员那里得到年龄歧视的评论。


let take = (arr, predicate, limit) => { 

  const results = [];

  const arrLength = arr.length 

  for (let i = 0; i < arrLength && results.length < limit; i++) { 

    if (predicate(arr[i])) { 

      results.push(arr[i]); 

    } 

  } 

  return results; 

}

无论如何,我很想知道其他人对此问题的解决方案,但这对我来说似乎非常有效......也许是原型垫片解决方案?


查看完整回答
反对 回复 2021-12-02
?
互换的青春

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

您可以使用生成器或可观察对象以相当优雅的方式完成此操作。


发电机

我实际上为此专门开发了一个小的 npm 包。


使用这个包和 Ramda,你可以得到你想要的结果,如下所示:


在 RunKit 中尝试


const { genTake, genFilter, genFrom, genToArray } = require("func-generators");

const { compose } = require('ramda');


const probe = x => (console.log(x),x);


const firstTwoUnderFour = compose(

    genToArray,

    genTake(2),

    genFilter(x => probe(x) < 4),  //  genFilter(x => x < 4),

    genFrom,    

);


console.log(firstTwoUnderFour([5,6,7,1,6,8,2,9,10,5]));  // [1, 2]

我在过滤谓词中添加了一个探针,以显示它正在处理哪些元素。您可以从控制台输出中看到它在到达 时立即停止2。

基本上,它在这里做的是:

  1. 从原始数组 ( genFrom)生成生成器函数

  2. 将该生成器函数转换为仅生成与谓词 ( genFilter(x => x < 4))匹配的值的生成器函数

  3. 将该生成器函数转换为仅从步骤 2 ( genTake(2)) 中的一个生成前两个值的生成器函数

  4. 将第 3 步中的生成器函数收敛到一个值数组 ( genToArray)

take从你发布的答案中更概括的可以写成这样:

const take = (arr, predicate, limit) => compose(

    genToArray,

    genTake(limit),

    genFilter(predicate),

    genFrom,

)(arr);

这甚至适用于无限的值序列:


在 RunKit 中尝试


const { genTake, genFilter, genInfinite, genToArray } = require("func-generators");

const { compose } = require('ramda');


const firstFiveMultiplesOf125 = compose(

    genToArray,

    genTake(5),

    genFilter(x => x % 125 === 0),

);


console.log(firstFiveMultiplesOf125(genInfinite()));

最后要注意的一件事:我在这里使用 Ramda 的 compose 来提高可读性,但您也可以嵌套这些函数调用,或者一个一个地调用它们:


const result = genToArray(gnTake(5, filter(x => x < 4, genFrom([1,2,3,4,5,6]))));


// or...


const gen = genFrom([1, 2, 3, 4, 5, 6]);

const first2 = genTake(2, genFilter(x => x < 4, gen));

const result = genToArray(first2);

可观察对象

一种稍微重量级的方法是使用 Observables,例如RxJS库:


在 RunKit 中尝试


const { from } = require("rxjs")

const { take, filter, toArray } = require('rxjs/operators');


const probe = x => (console.log(x),x);


from([5,6,7,1,6,8,2,9,10,5]).pipe(

    filter(x => probe(x) < 4),

    take(2),

    toArray(),

).subscribe(xs => console.log(xs));    // [1, 2]

您也可以在此处看到它在到达 时立即停止检查数组中的元素2。


查看完整回答
反对 回复 2021-12-02
?
繁星点点滴滴

TA贡献1803条经验 获得超3个赞

for ... of如果结果数组的长度为 2,您可以使用惰性求值循环并退出。


var array = [1, 2, 3, 4, 5, 6],

    result = [];


for (let item of array) {

    if (item < 4) if (result.push(item) === 2) break;

}


console.log(result);


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

添加回答

举报

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