过滤条件,带电路断开n

时间:2019-10-24 05:19:05

标签: javascript typescript

按条件进行过滤并先获取n个结果导致电路断路的最佳方法是什么?

在预定义的项目列表中考虑搜索过滤器:

[1, 2, 3, 4, 5, 6].filter(x => {
  console.log(x);
  return x < 4;
}).take(2) === [1, 2];
// 1
// 2
// true

take函数不存在,因为过滤器函数仅返回一个数组,我希望该流具有断路功能。是否存在使用功能性方法合成的成分?

// 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]

如果没有更多元素,该功能也应该停止。即

take([1, 2, 3], x => x < 4, 4) === [1, 2, 3]

6 个答案:

答案 0 :(得分:2)

感谢@GeraldoFurtado的哲学观点。 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; 
}

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

答案 1 :(得分:2)

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

发电机

我实际上是专门为此目的而开发的a little npm package

使用该软件包和Ramda,您可以这样获得所需的结果:

Try it in 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);

这甚至可以处理无限的值序列:

Try it in 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库:

Try it in 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,它就会停止检查数组中的元素。

答案 2 :(得分:1)

如果结果数组的长度为2,则可以进行for ... of循环并进行惰性计算,然后退出。

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);

答案 3 :(得分:0)

如果老的循环器不能带来美学上的满足,如果您使用嵌入式断路器,则可以(以某种不自然的方式)使用其中的高阶功能之一。像我一样沉迷于他们:

const arr = [2,6,9,8,4,3,7,5];

const res = [];

//first 3 items less than 8
arr.find(n => n<8 ? (res.push(n), res.length==3) : false, res);

console.log(res);

答案 4 :(得分:0)

使用lodash

take(filter([1, 2, 3, 4, 5, 6], x => x < 4), 2)

答案 5 :(得分:0)

const take = (array, predicate, length) => {
  let result= []
  let i = 0
  while (i <= array.length && result.length < length) {
    if (predicate(array[i])) {
      result.push(array[i])
    }
    i++
  }
  return result;
}

const test1 = take([1, 2, 3, 4, 5, 6], x => x < 4, 4)
console.log(test1)

const test2 = take([1, 2, 3, 4, 5, 6, 7, 8, 9], x => x % 2 === 0, 5)
console.log(test2)