2013-09-21 58 views
89

这里之后这个问题:的JavaScript相当于C#LINQ选择

Using the checked binding in knockout with a list of checkboxes checks all the checkboxes

我创建使用基因敲除一些复选框,允许从阵列选择。 工作拨弄从上述职位采取:

http://jsfiddle.net/NsCXJ/

有只创建水果的ID的数组的一个简单的方法?

我更在家里用C#,我会做沿着selectedFruits.select(fruit=>fruit.id);

线的东西是否有这样做的JavaScript/jQuery的类似的东西一些方法/现成的功能?或者最简单的选择是循环访问列表并创建第二个数组? 我打算在JSON中将数组发回服务器,所以我试图最小化发送的数据。

回答

146

是的,Array.map()$.map()做同样的事情。

//array.map: 
var ids = this.fruits.map(function(v){ 
    return v.Id; 
}); 

//jQuery.map: 
var ids2 = $.map(this.fruits, function (v){ 
    return v.Id; 
}); 

console.log(ids, ids2); 

http://jsfiddle.net/NsCXJ/1/

由于array.map不能在较早的浏览器支持,我建议你还是坚持使用jQuery的方法。

如果您因为某种原因更喜欢另一个,则可以随时添加一个polyfill以实现旧的浏览器支持。

您可以随时添加自定义方法的阵列原型,以及:

Array.prototype.select = function(expr){ 
    var arr = this; 
    //do custom stuff 
    return arr.map(expr); //or $.map(expr); 
}; 

var ids = this.fruits.select(function(v){ 
    return v.Id; 
}); 

如果你传递一个字符串,使用函数构造函数的扩展版本。东西玩弄也许是:

Array.prototype.select = function(expr){ 
    var arr = this; 

    switch(typeof expr){ 

     case 'function': 
      return $.map(arr, expr); 
      break; 

     case 'string': 

      try{ 

       var func = new Function(expr.split('.')[0], 
             'return ' + expr + ';'); 
       return $.map(arr, func); 

      }catch(e){ 

       return null; 
      } 

      break; 

     default: 
      throw new ReferenceError('expr not defined or not supported'); 
      break; 
    } 

}; 

console.log(fruits.select('x.Id')); 

http://jsfiddle.net/aL85j/

更新:

由于这已成为流行这样一种答案,我加入类似我where() + firstOrDefault()。这些也可以与基于字符串的函数的构造方法中使用(这是最快的),但这里是使用对象文本作为过滤另一种方法:

Array.prototype.where = function (filter) { 

    var collection = this; 

    switch(typeof filter) { 

     case 'function': 
      return $.grep(collection, filter); 

     case 'object': 
      for(var property in filter) { 
       if(!filter.hasOwnProperty(property)) 
        continue; // ignore inherited properties 

       collection = $.grep(collection, function (item) { 
        return item[property] === filter[property]; 
       }); 
      } 
      return collection.slice(0); // copy the array 
             // (in case of empty object filter) 

     default: 
      throw new TypeError('func must be either a' + 
       'function or an object of properties and values to filter by'); 
    } 
}; 


Array.prototype.firstOrDefault = function(func){ 
    return this.where(func)[0] || null; 
}; 

用法:

var persons = [{ name: 'foo', age: 1 }, { name: 'bar', age: 2 }]; 

// returns an array with one element: 
var result1 = persons.where({ age: 1, name: 'foo' }); 

// returns the first matching item in the array, or null if no match 
var result2 = persons.firstOrDefault({ age: 1, name: 'foo' }); 

这里是一个jsperf test来比较函数构造函数与对象文字速度。如果您决定使用前者,请记住正确引用字符串。

我个人的偏好是在过滤1-2个属性时使用基于对象字面值的解决方案,并为更复杂的过滤传递回调函数。

if(!Array.prototype.where) { Array.prototype.where = ...

  • 如果您:覆盖如之前

    1. 检查的现有方法发生:

      我会添加方法原生对象原型,用时2个一般提示结束这不需要支持IE8及以下版本,请使用Object.defineProperty定义方法,使它们不可枚举。如果有人在数组上使用了for..in(这首先是错误的) 它们也会迭代枚举属性。只是一个头。

  • +1

    @ChrisNevill我添加了一个字符串版本,以防万一你intrested – Johan

    +0

    @MUlferts良好的捕获,更新:)。现在我建议使用lodash来完成这些任务。他们公开了与上面的代码相同的接口 – Johan

    +0

    为了支持knockout observables:'return typeof item [property] ==='function'? item [property]()=== filter [property]:item [property] === filter [property];' –

    2

    查看underscore.js,它提供了很多类似linq的功能。在你给你的例子中会使用map函数。

    +1

    如果有人想知道他们是如何比较的,我发布了解释超过15个最流行的LINQ/underscore.js函数之间差异的博客文章:https://www.vladopandzic.com/javascript/comparing-underscore-js-with-linq/ –

    13

    由于您使用的是淘汰赛,因此您应该考虑使用淘汰赛实用程序函数arrayMap()以及它的其他阵列实用程序函数。

    这里的数组效用函数及其等价LINQ方法的列表:

    arrayFilter() -> Where() 
    arrayFirst() -> First() 
    arrayForEach() -> (no direct equivalent) 
    arrayGetDistictValues() -> Distinct() 
    arrayIndexOf() -> IndexOf() 
    arrayMap() -> Select() 
    arrayPushAll() -> (no direct equivalent) 
    arrayRemoveItem() -> (no direct equivalent) 
    compareArrays() -> (no direct equivalent) 
    

    所以,你可以在你的例子做的是这样的:

    var mapped = ko.utils.arrayMap(selectedFruits, function (fruit) { 
        return fruit.id; 
    }); 
    

    如果你想有一个LINQ像接口javascript,你可以使用一个库,例如linq.js,它为许​​多LINQ方法提供了一个很好的界面。

    var mapped = Enumerable.From(selectedFruits) 
        .Select("$.id") // 1 of 3 different ways to specify a selector function 
        .ToArray(); 
    
    2

    我有建TsLinq.codeplex.com下一个LINQ库打字稿,你可以使用普通的JavaScript了。该库比Linq.js快2-3倍,并包含所有Linq方法的单元测试。也许你可以评论一下。

    29

    我知道这是一个迟到的答案,但它对我有用!只需完成,使用$.grep函数即可模拟linq where()

    的LINQ:

    var maleNames = people 
    .Where(p => p.Sex == "M") 
    .Select(p => p.Name) 
    

    使用Javascript:

    // replace where with $.grep 
    //   select with $.map 
    var maleNames = $.grep(people, function (p) { return p.Sex == 'M'; }) 
          .map(function (p) { return p.Name; }); 
    
    +0

    这就是我想要的..但​​什么是更好的在你的答案和Enumerable.From(selectedFruits).Select(function(fruit){return fruit.id;}); – Bharat

    0

    Dinqyjs具有LINQ的语法和用于像图和的indexOf功能提供polyfills,并已被用于在Javascript中使用数组专门设计。

    8

    您也可以尝试linq.js

    linq.js

    selectedFruits.select(fruit=>fruit.id); 
    

    Enumerable.From(selectedFruits).Select(function (fruit) { return fruit.id; }); 
    
    7

    的ES6方式:

    let people = [{firstName:'Alice',lastName:'Cooper'},{firstName:'Bob',age:'Dylan'}]; 
    let names = Array.from(people, p => p.firstName); 
    for (let name of names) { 
        console.log(name); 
    } 
    

    人所以在:https://jsfiddle.net/52dpucey/

    +0

    非常感谢。我正在进入ES6,所以这可能会很方便! –