Javascript tương đương với C # LINQ Chọn


136

Sau câu hỏi này tại đây:

Sử dụng liên kết được kiểm tra trong loại trực tiếp với một danh sách các hộp kiểm tra tất cả các hộp kiểm

Tôi đã tạo một số hộp kiểm bằng cách sử dụng loại trực tiếp cho phép lựa chọn từ một mảng. Fiddle làm việc được lấy từ bài viết trên:

http://jsfiddle.net/NsCXJ/

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

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

Có một số phương thức / chức năng đã sẵn sàng để làm một cái gì đó tương tự với javascript / jquery? Hoặc tùy chọn đơn giản nhất sẽ 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ủ trong JSON vì vậy tôi đang cố gắng giảm thiểu dữ liệu được gửi.

Câu trả lời:


227

Có, Array.map () hoặc $ .map () thực hiện điều tương tự.

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

Vì Array.map không được hỗ trợ trong các trình duyệt cũ hơn, tôi khuyên bạn nên sử dụng phương thức jQuery.

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

Bạn luôn có thể thêm các phương thức tùy chỉnh vào nguyên mẫu mảng:

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 hàm tạo nếu bạn truyền chuỗi. Một cái gì đó để chơi xung quanh có 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, nên tôi thêm tương tự where()+ firstOrDefault(). Chúng cũng có thể được sử dụng với cách tiếp cận hàm xây dựng hàm dựa trên chuỗi (nhanh nhất), nhưng đây là một cách tiếp cận khác sử dụng một đối tượng theo nghĩa đen là bộ 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;
};

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

Dưới đây là một bài kiểm tra jsperf để so sánh hàm tạo hàm với tốc độ theo nghĩa đen của đối tượng. Nếu bạn quyết định sử dụng trước đây, hãy ghi nhớ để trích dẫn chuỗi chính xác.

Sở thích cá nhân của tôi là sử dụng các giải pháp dựa trên đối tượng khi lọc 1-2 thuộc tính và chuyển một hàm gọi lại để lọc phức tạp hơn.

Tôi sẽ kết thúc điều này bằng 2 mẹo chung khi thêm phương thức vào các nguyên mẫu đối tượng gốc:

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

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

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


1
@ChrisNevill Tôi cũng đã thêm một phiên bản chuỗi trong trường hợp bạn bị giới hạn
Johan

@MUlferts Bắt tốt, cập nhật :). Ngày nay tôi sẽ đề nghị sử dụng lodash cho các loại nhiệm vụ này. Họ để lộ giao diện giống như mã ở trên
Johan

Để hỗ trợ các thiết bị quan sát loại trực tiếp:return typeof item[property] === 'function' ? item[property]() === filter[property] : item[property] === filter[property];
Linus Caldwell

@LinusCaldwell Đã lâu lắm rồi tôi không sử dụng loại trực tiếp, nhưng còn cái gì đó như thế return ko.unwrap(item[property]) === filter[property]nào?
Johan

Vâng, tôi đã đề cập đến loại trực tiếp, nhưng tất nhiên điều này sẽ bao gồm tất cả các thuộc tính là các hàm không có tham số bắt buộc. Bên cạnh đó, tại sao một người sẽ phá vỡ phong cách chung của mã đẹp của bạn?
Linus Caldwell

33

Tôi biết đó là một câu trả lời muộn nhưng nó rất hữu ích với tôi! Chỉ cần hoàn thành, sử dụng $.grepchức năng 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; });

đó là những gì tôi muốn..nhưng điều gì tốt hơn ở giữa câu trả lời của bạn và Enumerable.From (selectFruits) .Select (function (fruit) {return fruit.id;});
Bharat

15

Vì bạn đang sử dụng loại trực tiếp, bạn nên cân nhắc sử dụng chức năng tiện ích loại trực tiếp arrayMap()và đó là các chức năng tiện ích mảng khác.

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

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à:

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

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

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

14

Cách 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);
}

cũng tại: https://jsfiddle.net/52dpucey/


Nhiều đánh giá cao. Tôi mới vào ES6 nên việc này có thể hữu ích!
Chris Nevill

10

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

Trong linq.jsbạn

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

sẽ là

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

4

Tôi đã xây dựng thư viện Linq cho TypeScript trong TsLinq.codeplex.com mà bạn cũng có thể sử dụng cho javascript đơn giản. Thư viện đó nhanh hơn 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 đó.




0

Dinqyjs có cú pháp giống linq và cung cấp các polyfill cho các chức năng như map và indexOf, và đã được thiết kế đặc biệt để làm việc với các mảng trong Javascript.


0

Hãy nhìn vào một cách trôi chảy , nó hỗ trợ hầu hết mọi thứ LINQ làm và dựa trên các lần lặp - vì vậy nó hoạt động với các bản đồ, các hàm tạo, mảng, mọi thứ có thể lặp lại.



-1

Tôi đang trả lời tiêu đề của câu hỏi hơn là câu hỏi ban đầu cụ thể hơn.

Với các tính năng mới của Javascript như các trình lặp và các hàm và đối tượng của trình tạo, một cái gì đó như LINQ cho Javascript trở nên khả thi. Lưu ý rằng, ví dụ linq.js sử dụng một cách tiếp cận hoàn toàn khác, sử dụng các biểu thức thông thường, có thể để khắc phục sự thiếu hỗ trợ trong ngôn ngữ tại thời điểm đó.

Như đã nói, tôi đã viết một thư viện LINQ cho Javascript và bạn có thể tìm thấy nó tại https://github.com/Siderite/LInQer . Nhận xét và thảo luận tại https://siderite.dev/blog/linq-in-javascript-linqer .

Từ các câu trả lời trước đó, chỉ Manipula dường như là những gì người ta mong đợi từ một cổng LINQ trong Javascript.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.