2013-09-21 48 views
89

Tiếp theo câu hỏi này ở đây:Javascript Tương đương với C# LINQ Chọn

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

tôi đã tạo ra một số hộp kiểm bằng knock-out cho phép lựa chọn từ một mảng. làm việc fiddle lấy từ trên bài:

http://jsfiddle.net/NsCXJ/

Có một cách đơn giản để tạo ra một mảng chỉ ID của trái cây?

tôi nhiều hơn ở nhà với C# nơi tôi sẽ làm điều gì đó dọc theo dòng của selectedFruits.select(fruit=>fruit.id);

Có một số phương pháp/sẵn sàng thực hiện chức năng để thực hiện điều gì đó tương tự với javascript/jquery? Hoặc sẽ là lựa chọn đơn giản nhất để lặp qua danh sách và tạo một mảng thứ hai? Tôi dự định đăng mảng trở lại máy chủ bằng JSON nên cố gắng giảm thiểu dữ liệu được gửi.

Trả lời

146

Có, Array.map() hoặc $.map() cũng làm như vậy.

//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/

Kể từ array.map không được hỗ trợ trong các trình duyệt cũ, tôi đề nghị bạn nên gắn bó với phương pháp jQuery.

Nếu bạn thích một lý do khác vì một lý do nào đó bạn luôn có thể thêm một polyfill cho hỗ trợ trình duyệt cũ.

Bạn luôn có thể thêm các phương pháp tùy chỉnh để nguyên mẫu mảng cũng như:

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

Một phiên bản mở rộng sử dụng các nhà xây dựng chức năng nếu bạn vượt qua một chuỗi. Một cái gì đó để chơi xung quanh với lẽ:

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/

Cập nhật:

Vì đây đã trở thành một câu trả lời phổ biến như vậy, tôi thêm tương tự như tôi where() + firstOrDefault(). Đây cũng có thể được sử dụng với các chuỗi dựa phương pháp hàm xây dựng (đó là nhanh nhất), nhưng đây là một cách tiếp cận sử dụng một đối tượng theo nghĩa đen như lọc:

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

Cách sử dụng:

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

Đây là một jsperf test để so sánh hàm tạo hàm so với tốc độ chữ của đối tượng. Nếu bạn quyết định sử dụng tên cũ, hãy nhớ trích dẫn chính xác các chuỗi.

sở thích cá nhân của tôi là sử dụng các đối tượng giải pháp dựa theo nghĩa đen khi lọc 1-2 thuộc tính, và vượt qua một chức năng gọi lại cho việc lọc phức tạp hơn.

tôi sẽ kết thúc chuyện này với 2 lời khuyên chung khi thêm phương pháp để nguyên mẫu đối tượng bẩm sinh:

  1. Kiểm tra cho sự xuất hiện của các phương pháp hiện có trước khi ghi đè lên ví dụ:

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

  2. Nếu bạn không cần phải hỗ trợ IE8 trở xuống, xác định các phương thức sử dụng Object.defineProperty để làm cho chúng không thể đếm được. Nếu ai đó sử dụng for..in trên một mảng (đó là sai ở nơi đầu tiên) họ sẽ lặp lại các thuộc tính đếm là tốt. Chỉ cần một đầu lên.

+1

@ChrisNevill Tôi đã thêm phiên bản chuỗi cũng như trong trường hợp bạn bị xâm nhập – Johan

+0

@MUlferts Bắt kịp, cập nhật :). Ngày nay tôi sẽ đề nghị sử dụng lodash cho những loại nhiệm vụ này. Chúng lộ diện tương tự như mã trên – Johan

+0

Để hỗ trợ các quan sát loại trực tiếp: 'kiểu trả về của mục [thuộc tính] === 'chức năng'? item [property]() === filter [property]: item [property] === filter [property]; ' –

2

Xem nhanh underscore.js cung cấp nhiều chức năng giống như LINQ. Trong ví dụ bạn cung cấp cho bạn sẽ sử dụng chức năng bản đồ.

+1

Nếu ai đó muốn biết họ so sánh bài viết trên blog của tôi như thế nào, giải thích sự khác biệt giữa hơn 15 chức năng LINQ/underscore.js phổ biến nhất: https://www.vladopandzic.com/javascript/comparing-underscore-js-with-linq/ –

13

Vì bạn đang sử dụng loại trực tiếp, bạn nên xem xét sử dụng các chức năng tiện ích knock-out arrayMap() và đó là chức năng tiện ích mảng khác.

Dưới đây là một danh sách các chức năng tiện ích mảng và phương pháp LINQ tương đương của họ:

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) 

Vì vậy, những gì bạn có thể làm trong ví dụ của bạn là thế này:

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

Nếu bạn muốn có một LINQ như giao diện trong javascript, bạn có thể sử dụng một thư viện như linq.js cung cấp giao diện đẹp cho nhiều phương pháp LINQ.

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

Tôi đã tạo thư viện Linq cho TypeScript dưới TsLinq.codeplex.com mà bạn có thể sử dụng cho javascript thuần túy. Thư viện đó nhanh gấp 2-3 lần so với Linq.js và chứa các bài kiểm tra đơn vị cho tất cả các phương thức Linq. Có lẽ bạn có thể xem lại cái đó.

29

Tôi biết đó là câu trả lời trễ nhưng nó hữu ích cho tôi! Chỉ cần hoàn thành, sử dụng hàm $.grep bạn có thể mô phỏng 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

đó là những gì tôi muốn .. nhưng những gì là tốt hơn ở giữa câu trả lời của bạn và Enumerable.From (selectedFruits) .Chọn (chức năng (trái cây) {return fruit.id;}); – Bharat

0

Dinqyjs có một cú pháp LINQ-like và cung cấp polyfills cho các chức năng như bản đồ và indexOf, và đã được thiết kế đặc biệt để làm việc với mảng trong Javascript .

8

Bạn cũng có thể thử linq.js

Trong linq.js bạn

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

sẽ

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

Các ES6 cách:

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

al tại: https://jsfiddle.net/52dpucey/

+0

Được đánh giá cao. Tôi chỉ đi vào ES6 để điều này có thể tiện dụng! –