2013-09-21 120 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,所以這可能會很方便! –