fp-ts: массив фильтров на основе следующего элемента - PullRequest
0 голосов
/ 04 мая 2020

Я начинаю с функционального программирования / fp-ts. Я пытаюсь написать функцию, которая, принимая список, сохраняет элемент, если выполнено условие для элемента next .

Пример:

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

I может также понадобиться расширить это так, чтобы и совпадение и следующий элемент были включены, как:

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

Я понятия не имею, как построить правильную чистую функцию, чтобы сделать это для любой из двух.

Любые намеки приветствуются.

Ответы [ 2 ]

1 голос
/ 05 мая 2020

Дайте мне знать, если это работает

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)
}
0 голосов
/ 05 мая 2020

Во-первых, позвольте мне показать вам код:

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

Во-вторых, вы пишете «если условие для элемента следующий выполнено», но ваш пример показывает, что условие должно пройти на предыдущий один. Код для вашего примера.

Эта задача состоит из трех частей:

  1. Подготовка данных для фильтра
  2. Фильтр
  3. Извлеките то, что вам нужно

Магическая функция Array.zip , которая создает пары из двух массивов.

Я запускаю его с исходным массивом и смещенным (с удаленным первым элементом) массивом. Это создает пары, в которых первое значение в паре является исходным значением, а второе - значением, на котором должно выполняться условие.

Поскольку Array.tail возвращает Option (не возвращает ничего, если массив пусто), нам нужно выполнить его сначала Option.getOrElse.

На последнем шаге после фильтрации пар я сопоставляю их и беру исходное значение из каждой пары.

Пока Я использую пару, вы можете использовать объект или другую структуру. Мне нравятся пары, потому что их легко набирать и работать с ними благодаря деструктуризации массива.

Как изменить поведение:

  • filterOnNext : переключить A.zip(tail, xs) в A.zip(xs, tail). Опять же, первое значение - это оригинал, второе - то, на котором должно выполняться условие. В качестве альтернативы, обновите A.filter и A.map, чтобы оно использовало другое значение в паре.
  • Оставьте оба : это сложно, потому что, если, например, три числа в строке удовлетворяют условию Не ясно, каков желаемый результат. В любом случае, я бы по-прежнему рекомендовал сначала создать пару с одним значением, являющимся результатом, если условие переходит ко второму значению.
...