【问题标题】:Equivalent to LINQ's Enumerable.First(predicate)等效于 LINQ Enumerable.First(predicate)
【发布时间】:2015-04-13 03:20:16
【问题描述】:

在 C# 中,我们有 Enumerable.First(predicate)。鉴于此 JavaScript 代码:

function process() {
  var firstMatch = ['a', 'b', 'c'].filter(function(e) {
    return applyConditions(e);
  }).shift();

  if(!firstMatch) {
    return;
  }

  // do something else
}

function applyConditions(element) {
  var min = 97;
  var max = 122;

  var random = Math.floor(Math.random() * (max - min + 1) + min);

  return element === String.fromCharCode(random);
}

除了forEach,使用循环,使用多个或运算符或隐式调用some(predicate),有没有更聪明的方法来找到firstMatch?最好是一个 JavaScript 函数(类似于 filterFirst(pedicate)),它在第一次匹配时短路,类似于 C# 的 Enumerable.First() 实现?

FWIW,我的目标是 node.js / io.js 运行时。

【问题讨论】:

    标签: javascript arrays node.js linq filter


    【解决方案1】:

    无需重新发明轮子,正确的做法是使用.find

    var firstMatch = ['a', 'b', 'c'].find(applyConditions);
    

    如果您使用的浏览器不支持.find,您可以使用polyfill it

    【讨论】:

    • +1 是的 .find(predicate) 正是我在 node.js 中寻找的。这仍处于试验阶段,规范状态为草稿。
    • 公平地说,这不是真的实验性的 :) 草案已经确定,他们现在正在弄清楚其他东西的语义。
    • First in c# 如果没有任何匹配项,则会引发异常。所以,find 等价于FirstOrDefault
    • 顺便说一句,如果没有项目符合条件,find() 将返回 undefined。
    • 正如 Hamid 指出的那样,这并不等同于 First。这相当于FirstOrDefault,所以虽然这对寻找类似问题的人有帮助,但对这个问题并没有真正的帮助。
    【解决方案2】:

    你可以在你想用reduce返回第一个truthy值的情况下模拟这个。

    ['a', 'b', 'c'].reduce(function(prev, curr) { 
        return prev || predicate(curr) && curr; 
    }, false);
    

    编辑:使用@BenjaminGruenbaum 的建议更简洁

    【讨论】:

    • 花花公子! reduce() 非常接近,除了它为数组的每个元素调用回调(而不是在第一次匹配时短路)。
    • @vulcanraven 我不认为它是这样的——这真的让人很困惑——它可以写成return prev || predicate(curr) && curr——它也会因为错误的数组元素而失败(例如找到 0)。
    • @BenjaminGruenbaum reduce 总是调用整个数组的回调,它不会短路
    • @Esailija 它调用回调,但不检查谓词。
    • @BenjaminGruenbaum,为了不那么复杂,考虑callback === predicate。它为每个元素调用回调并且不会短路。想想具有巨大尺寸的数组,其中数组的大小很重要,算法的复杂性取决于输入数组的排序。这意味着在某些用例中,短路会产生很大的影响。我正在寻找的是.find(),您[在下面的答案中描述]。(stackoverflow.com/a/28477788/863980)。现在等待 ECMAScript 6 的和谐。:)
    【解决方案3】:

    LINQ 用户在没有谓词的情况下多次调用firstfirstOrDefault,而find 则不可能。所以,

      first() {
        var firstOrDefault = this.firstOrDefault();
        if(firstOrDefault !== undefined)
          return firstOrDefault;
        else
          throw new Error('No element satisfies the condition in predicate.');
      }
    
      firstOrDefault() {
        return this.find(o => true);
      }
    

    【讨论】:

    • 或者对于第一个真实值,this.find(o => o)
    【解决方案4】:

    如果你想创建可重用的东西: 先定义一个谓词类型

    declare global {
      type predicate<T> = (arg: T) => boolean;
    }
    

    然后在数组上定义原型函数:

      if (!Array.prototype.First) {
      Array.prototype.First = function <T>(condition: predicate<T>): T {
        let matchingItems: T[] = this.filter((item: T) => {
          if (condition(item))
            return item;
        });
        if (matchingItems === null || matchingItems === undefined || matchingItems.length === 0) {
          throw Error('Invalid operation. No items found.');
        }
        return matchingItems[0];
      }
    }
    

    现在您可以在数组上调用方法“First”并传入谓词。这里还支持返回布尔值的任何函数,例如您的函数“applyConditions”。

    【讨论】:

      【解决方案5】:

      有几个包:
      linq.js - 用于 JavaScript 的 LINQ https://github.com/mihaifm/linq/
      npm install linq

      这是 .NET LINQ 库的 JavaScript 实现。

      它包含所有原始 .NET 方法以及一些附加功能。

      用纯 JavaScript 编写,没有依赖关系。

      https://www.npmjs.com/package/linq-to-typescript

      为 TypeScript 实现 LINQ

      await from([bing, google, quackQuackGo])
          .asParallel()
          .selectAsync(downloadHtml)
          .select(getTitle)
          .toArray()
      

      https://www.npmjs.com/package/linq-typescript

      【讨论】:

        猜你喜欢
        • 2020-12-11
        • 1970-01-01
        • 1970-01-01
        • 2011-08-22
        • 1970-01-01
        • 2018-01-02
        • 1970-01-01
        • 2011-02-16
        • 2013-09-27
        相关资源
        最近更新 更多