Javascript相当于c# LINQ Select

时间:2022-08-09 15:46:15

Following this question here :

接下来的问题是:

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

在knockout中使用选中的绑定和复选框的列表来检查所有的复选框。

I've created some checkboxes using knockout that allow selection from an array. working fiddle taken from above post:

我使用knockout创建了一些复选框,允许从数组中进行选择。上列工作小提琴:

http://jsfiddle.net/NsCXJ/

http://jsfiddle.net/NsCXJ/

Is there a simple way of creating an array of just the fruit's ID's?

是否有一种简单的方法来创建一个只包含水果ID的数组?

I'm more at home with C# where I would do something along the lines of selectedFruits.select(fruit=>fruit.id);

我对c#比较熟悉,在c#中我可以按照选择的水果做一些事情。select(水果=>fruit.id);

Is there some method/ready made function for doing something similar with javascript/jquery? Or would the simplest option be to loop through the list and create a second array? I intend to post the array back to the server in JSON so am trying to minimize the data sent.

有什么方法/现成的函数可以用javascript/jquery做类似的事情吗?或者最简单的选择是循环遍历列表并创建第二个数组?我打算将数组以JSON格式发送回服务器,因此我试图最小化发送的数据。

8 个解决方案

#1


156  

Yes, Array.map() or $.map() does the same thing.

是的,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/

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

Since array.map isn't supported in older browsers, I suggest that you stick with the jQuery method.

因为数组。旧浏览器不支持map,我建议您继续使用jQuery方法。

If you prefer the other one for some reason you could always add a polyfill for old browser support.

如果您出于某种原因喜欢另一个,您可以为旧的浏览器支持添加一个polyfill。

You can always add custom methods to the array prototype as well:

也可以在数组原型中添加自定义方法:

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

An extended version that uses the function constructor if you pass a string. Something to play around with perhaps:

传递字符串时使用函数构造函数的扩展版本。也许有什么值得玩味的东西:

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/

http://jsfiddle.net/aL85j/

Update:

更新:

Since this has become such a popular answer, I'm adding similar my where() + firstOrDefault(). These could also be used with the string based function constructor approach (which is the fastest), but here is another approach using an object literal as filter:

由于这已经成为如此流行的答案,我添加了类似的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;
};

Usage:

用法:

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

Here is a jsperf test to compare the function constructor vs object literal speed. If you decide to use the former, keep in mind to quote strings correctly.

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

My personal preference is to use the object literal based solutions when filtering 1-2 properties, and pass a callback function for more complex filtering.

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

I'll end this with 2 general tips when adding methods to native object prototypes:

在向本机对象原型添加方法时,我将以两个一般技巧作为结尾:

  1. Check for occurrence of existing methods before overwriting e.g.:

    在覆盖之前检查现有方法的出现情况,例如:

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

    如果(! Array.prototype.where){ Array.prototype。在哪里=…

  2. If you don't need to support IE8 and below, define the methods using Object.defineProperty to make them non-enumerable. If someone used for..in on an array (which is wrong in the first place) they will iterate enumerable properties as well. Just a heads up.

    如果不需要支持IE8和以下版本,请使用Object.defineProperty定义方法,使它们不可枚举。如果有人用于. .在数组中(首先是错误的),它们也将迭代可枚举属性。只是一个头。

#2


29  

I know it is a late answer but it was useful to me! Just to complete, using the $.grep function you can emulate the linq where().

我知道这是一个迟来的答案,但它对我很有用!只需要用$来完成。grep函数可以模拟linq()。

Linq:

Linq:

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

Javascript:

Javascript:

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

#3


13  

Since you're using knockout, you should consider using the knockout utility function arrayMap() and it's other array utility functions.

由于使用的是knockout,所以应该考虑使用knockout实用程序函数arrayMap()和其他数组实用程序函数。

Here's a listing of array utility functions and their equivalent LINQ methods:

下面列出了阵列实用函数及其等效的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)

So what you could do in your example is this:

在你的例子中你可以做的是

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

If you want a LINQ like interface in javascript, you could use a library such as linq.js which offers a nice interface to many of the LINQ methods.

如果希望在javascript中使用类似LINQ的接口,可以使用LINQ之类的库。它为许多LINQ方法提供了一个很好的接口。

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

#4


8  

You can also try linq.js

您也可以尝试linq.js

In linq.js your

在linq中。js你

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

will be

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

#5


7  

The ES6 way:

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

also at: https://jsfiddle.net/52dpucey/

还在:https://jsfiddle.net/52dpucey/

#6


2  

Take a peek at underscore.js which provides many linq like functions. In the example you give you would use the map function.

看看下划线。它提供了许多类似linq的函数。在您给出的示例中,将使用映射函数。

#7


2  

I have build a Linq library for TypeScript under TsLinq.codeplex.com that you can use for plain javascript too. That library is 2-3 times faster than Linq.js and contains unit tests for all Linq methods. Maybe you could review that one.

我在TsLinq.codeplex.com上为打字稿构建了一个Linq库,你也可以将其用于普通的javascript。那个库比Linq快2-3倍。包含所有Linq方法的单元测试。也许你可以复习一下。

#8


0  

Dinqyjs has a linq-like syntax and provides polyfills for functions like map and indexOf, and has been designed specifically for working with arrays in Javascript.

Dinqyjs具有类似于linq的语法,并为诸如map和indexOf之类的函数提供了多填充,并专门为在Javascript中使用数组而设计。

#1


156  

Yes, Array.map() or $.map() does the same thing.

是的,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/

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

Since array.map isn't supported in older browsers, I suggest that you stick with the jQuery method.

因为数组。旧浏览器不支持map,我建议您继续使用jQuery方法。

If you prefer the other one for some reason you could always add a polyfill for old browser support.

如果您出于某种原因喜欢另一个,您可以为旧的浏览器支持添加一个polyfill。

You can always add custom methods to the array prototype as well:

也可以在数组原型中添加自定义方法:

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

An extended version that uses the function constructor if you pass a string. Something to play around with perhaps:

传递字符串时使用函数构造函数的扩展版本。也许有什么值得玩味的东西:

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/

http://jsfiddle.net/aL85j/

Update:

更新:

Since this has become such a popular answer, I'm adding similar my where() + firstOrDefault(). These could also be used with the string based function constructor approach (which is the fastest), but here is another approach using an object literal as filter:

由于这已经成为如此流行的答案,我添加了类似的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;
};

Usage:

用法:

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

Here is a jsperf test to compare the function constructor vs object literal speed. If you decide to use the former, keep in mind to quote strings correctly.

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

My personal preference is to use the object literal based solutions when filtering 1-2 properties, and pass a callback function for more complex filtering.

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

I'll end this with 2 general tips when adding methods to native object prototypes:

在向本机对象原型添加方法时,我将以两个一般技巧作为结尾:

  1. Check for occurrence of existing methods before overwriting e.g.:

    在覆盖之前检查现有方法的出现情况,例如:

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

    如果(! Array.prototype.where){ Array.prototype。在哪里=…

  2. If you don't need to support IE8 and below, define the methods using Object.defineProperty to make them non-enumerable. If someone used for..in on an array (which is wrong in the first place) they will iterate enumerable properties as well. Just a heads up.

    如果不需要支持IE8和以下版本,请使用Object.defineProperty定义方法,使它们不可枚举。如果有人用于. .在数组中(首先是错误的),它们也将迭代可枚举属性。只是一个头。

#2


29  

I know it is a late answer but it was useful to me! Just to complete, using the $.grep function you can emulate the linq where().

我知道这是一个迟来的答案,但它对我很有用!只需要用$来完成。grep函数可以模拟linq()。

Linq:

Linq:

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

Javascript:

Javascript:

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

#3


13  

Since you're using knockout, you should consider using the knockout utility function arrayMap() and it's other array utility functions.

由于使用的是knockout,所以应该考虑使用knockout实用程序函数arrayMap()和其他数组实用程序函数。

Here's a listing of array utility functions and their equivalent LINQ methods:

下面列出了阵列实用函数及其等效的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)

So what you could do in your example is this:

在你的例子中你可以做的是

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

If you want a LINQ like interface in javascript, you could use a library such as linq.js which offers a nice interface to many of the LINQ methods.

如果希望在javascript中使用类似LINQ的接口,可以使用LINQ之类的库。它为许多LINQ方法提供了一个很好的接口。

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

#4


8  

You can also try linq.js

您也可以尝试linq.js

In linq.js your

在linq中。js你

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

will be

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

#5


7  

The ES6 way:

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

also at: https://jsfiddle.net/52dpucey/

还在:https://jsfiddle.net/52dpucey/

#6


2  

Take a peek at underscore.js which provides many linq like functions. In the example you give you would use the map function.

看看下划线。它提供了许多类似linq的函数。在您给出的示例中,将使用映射函数。

#7


2  

I have build a Linq library for TypeScript under TsLinq.codeplex.com that you can use for plain javascript too. That library is 2-3 times faster than Linq.js and contains unit tests for all Linq methods. Maybe you could review that one.

我在TsLinq.codeplex.com上为打字稿构建了一个Linq库,你也可以将其用于普通的javascript。那个库比Linq快2-3倍。包含所有Linq方法的单元测试。也许你可以复习一下。

#8


0  

Dinqyjs has a linq-like syntax and provides polyfills for functions like map and indexOf, and has been designed specifically for working with arrays in Javascript.

Dinqyjs具有类似于linq的语法,并为诸如map和indexOf之类的函数提供了多填充,并专门为在Javascript中使用数组而设计。