【问题标题】:Reducing a set of predicate functions减少一组谓词函数
【发布时间】:2019-03-15 22:42:50
【问题描述】:

我有一组谓词进入我们将调用的函数searchForAcceptableNumber

searchForAcceptableNumber(arrayOfNumbers: number[], ...isNumberAcceptablePredicates: Array<(aNumber: number) => boolean>): number[] {
    const acceptableNumbers: number[] = [];

    const isNumberAcceptablePredicate: (aNumber: number) => boolean = (aNumber: number) => {
        const isLabelAcceptableReducer = (accumulator, currentValue) => accumulator && currentValue(aNumber);
        return isNumberAcceptablePredicates.reduce(isLabelAcceptableReducer);
    };

    arrayOfNumbers.forEach((aNumber: number) => {
        if (isNumberAcceptablePredicate(aNumber)) {
            acceptableNumbers.push(aNumber);
        }
    });
    return acceptableNumbers;
}

你明白了。本质上它会迭代,一切都很好......除了isNumberAcceptablePredicate不断收到(aNumber: number) =&gt; (aNumber: number) =&gt; boolean类型的错误。我可以摆脱这种类型,它会全部编译并正常工作。奇怪的是,如果我在调试会话期间将鼠标悬停在isNumberAcceptablePredicate 上,它会说它确实是(aNumber: number) =&gt; boolean 类型。

这不一定是代码破坏,也就是说,我最终将这个谓词传递给其他需要(aNumber: number) =&gt; boolean 类型的函数,所以它确实引入了代码破坏和这个额外的限制。我确定我错过了一些荒谬的东西,我就是不知道是什么。

【问题讨论】:

  • 只需将初始值传递给reduce:return isNumberAcceptablePredicates.reduce(isLabelAcceptableReducer, true);,这样如果数组isNumberAcceptablePredicates 包含一个元素(函数),结果将是true(布尔值)而不是数组中的(唯一)函数。
  • 祝福你,善良的陌生人。
  • 顺便说一句,您可以使用filter 而不是forEach 进行实际过滤:return arrayOfNumbers.filter((aNumber: number) =&gt; isNumberAcceptablePredicate(aNumber));。这样你就不需要数组acceptableNumbers
  • 我会做得更好:arrayOfNumbers.filter((aNumber) =&gt; isNumberAcceptablePredicates.every((pred) =&gt; pred(aNumber)));

标签: javascript typescript reducers


【解决方案1】:

你只需要为reduce函数提供一个初始值,否则它默认使用数组中的第一个元素作为初始值,其类型为(aNumber: number) =&gt; boolean而不是boolean

function searchForAcceptableNumber(
  arrayOfNumbers: number[],
  ...isNumberAcceptablePredicates: Array<(aNumber: number) => boolean>
): number[] {
  const acceptableNumbers: number[] = []

  const isNumberAcceptablePredicate: (aNumber: number) => boolean = (
    aNumber: number,
  ) => {
    const isLabelAcceptableReducer = (accumulator, currentValue) =>
      accumulator && currentValue(aNumber)
    return isNumberAcceptablePredicates.reduce(isLabelAcceptableReducer, true) // <-- initialise to true
  }

  arrayOfNumbers.forEach((aNumber: number) => {
    if (isNumberAcceptablePredicate(aNumber)) {
      acceptableNumbers.push(aNumber)
    }
  })
  return acceptableNumbers
}

你也可以使用一些内置的数组函数来大大缩短这个函数

function searchForAcceptableNumber(
  arrayOfNumbers: number[],
  ...isNumberAcceptablePredicates: Array<(aNumber: number) => boolean>
): number[] {
  return arrayOfNumbers.filter(number =>
    isNumberAcceptablePredicates.every(predicate => predicate(number)),
  )
}

如果您想概括实现,您可以执行以下操作

function filterList<T>(
  values: T[],
  predicates: Array<(val: T) => boolean>,
): T[] {
  return values.filter(val => predicates.every(pred => pred(val)))
}

你也可以使用箭头函数,因为函数只返回一个值,有些人更喜欢它的简洁性

const filterList = <T extends any>(
  values: T[],
  predicates: Array<(val: T) => boolean>,
): T[] => values.filter(val => predicates.every(pred => pred(val)))

注意:&lt;T extends any&gt; 的原因尽管extends any 在语义上是多余的,但这是必要的,因为单独的&lt;T&gt; 在语法上是不明确的,可能会被视为JSX 标记

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-20
    • 2021-01-23
    • 2010-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多