Javascript相当于C#LINQ Select

Chr*_*ill 123 javascript jquery knockout.js

在这里提出这个问题:

使用已敲除的已检查绑定和复选框列表检查所有复选框

我创建了一些使用knockout的复选框,允许从数组中进行选择.从上面的帖子取得的工作小提琴:

http://jsfiddle.net/NsCXJ/

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

我更喜欢在C#的家里,我会做一些事情 selectedFruits.select(fruit=>fruit.id);

是否有一些方法/现成功能用于执行类似于javascript/jquery的操作?或者最简单的选择是循环遍历列表并创建第二个数组?我打算用JSON将数组发回服务器,所以我试图最小化发送的数据.

Joh*_*han 210

是的,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);
Run Code Online (Sandbox Code Playgroud)

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;
});
Run Code Online (Sandbox Code Playgroud)

传递字符串时使用函数构造函数的扩展版本.或许可以玩的东西:

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'));
Run Code Online (Sandbox Code Playgroud)

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;
};
Run Code Online (Sandbox Code Playgroud)

用法:

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' }); 
Run Code Online (Sandbox Code Playgroud)

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

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

在向原生对象原型添加方法时,我将以2个一般提示结束:

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

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

  2. 如果您不需要支持IE8及更低版本,请使用Object.defineProperty定义方法,使其不可枚举.如果有人for..in在数组上使用(首先是错误的),他们也会迭代可枚举的属性.只是一个抬头.

  • @ChrisNevill 我还添加了一个字符串版本,以防您感兴趣 (2认同)

Ste*_*eri 32

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

LINQ:

var maleNames = people
.Where(p => p.Sex == "M")
.Select(p => p.Name)
Run Code Online (Sandbox Code Playgroud)

使用Javascript:

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


Jef*_*ado 13

由于你正在使用knockout,你应该考虑使用knockout实用程序函数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)
Run Code Online (Sandbox Code Playgroud)

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

var mapped = ko.utils.arrayMap(selectedFruits, function (fruit) {
    return fruit.id;
});
Run Code Online (Sandbox Code Playgroud)

如果你想在javascript中使用类似LINQ的接口,你可以使用像linq.js这样的库,它为许多LINQ方法提供了一个很好的接口.

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


Jul*_*ech 11

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);
}
Run Code Online (Sandbox Code Playgroud)

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


Ani*_*bhi 9

你也可以试试 linq.js

linq.js你的

selectedFruits.select(fruit=>fruit.id);
Run Code Online (Sandbox Code Playgroud)

将会

Enumerable.From(selectedFruits).Select(function (fruit) { return fruit.id;  });
Run Code Online (Sandbox Code Playgroud)