fp-ts:根据下一个元素过滤数组

fp-ts: Filter array based on next element

我从函数式编程开始/fp-ts。 我正在尝试编写一个函数,如果满足 next 元素上的条件,它会获取一个列表并保留一个元素。

示例:

const condition = (i: number) => i % 10 === 0;
filterNext(condition, [19, 20, 3, 18, 8, 48, 20, 4, 10]) // => [3, 4]

我可能还需要对此进行扩展,以便 包含匹配项和下一个元素,如:

const condition = (i: number) => i % 10 === 0;
filterNext(condition, [19, 20, 3, 18, 8, 48, 90, 4, 10]) // => [10, 3, 90, 4, 10]

我不知道如何为两者中的任何一个构建一个合适的纯函数。

欢迎任何提示。

让我知道这是否有效

import {Predicate, Refinement} from 'fp-ts/lib/function'
import {filterWithIndex} from 'fp-ts/lib/Array'
function filterWithNext<A>(predicate: Predicate<A>, xs: Array<A>): Array<A>
function filterWithNext<A, B extends A>(
  predicate: Refinement<A, B>,
  xs: Array<A>
): Array<B> {
  return filterWithIndex<A, B>(
    (i, x): x is B => predicate(x) && i !== xs.length && predicate(xs[i + 1])
  )(xs)
}

首先,让我向您展示代码:

import * as O from "fp-ts/lib/Option";
import * as A from "fp-ts/lib/Array";
import { pipe } from "fp-ts/lib/pipeable";

const filterOnPrevious = <T>(condition: (T) => boolean, xs: T[]): T[] =>
  pipe(
    A.tail(xs),
    O.getOrElse<T[]>(() => []),
    tail => A.zip(tail, xs),
    A.filter(([_, x]) => condition(x)),
    A.map(([x]) => x)
  );

其次,您写的是“如果满足 next 元素上的条件”,但您的示例表明该条件应该传递给 previous 一。该代码适用于您的示例。

该任务分为三个部分:

  1. 为过滤器准备数据
  2. 过滤器
  3. 提取你需要的

神奇的函数是Array.zip,它从两个数组中创建对。

I 运行 它与原始数组和一个移位(删除第一个元素)数组。这将创建对,其中对中的第一个值是原始值,第二个是条件应为 运行.

的值

因为Array.tailreturns一个Option(returnsnone如果数组为空),我们需要运行它通过Option.getOrElse 首先.

在最后一步,过滤对之后,我映射它们并从每对中获取原始值。

虽然我使用一对,但您可以使用对象或其他结构。我喜欢成对的,因为由于数组解构,它们很容易输入和使用。

如何改变行为:

  • filterOnNext:将 A.zip(tail, xs) 切换为 A.zip(xs, tail)。同样,第一个值是原始值,第二个是条件应为 运行 的值。或者,更新 A.filterA.map 以便它使用对中的另一个值。
  • 两者都保留:这很棘手,因为如果连续三个数字满足条件不清楚期望的结果是什么。无论如何,如果条件传递给第二个值,我仍然建议首先创建一对,其中一个值为结果。