web-dev-qa-db-ja.com

C#LINQ Selectと同等のJavascript

ここでこの質問に続いて:

チェックボックスのリストでノックアウトのチェック済みバインディングを使用すると、すべてのチェックボックスがチェックされます

ノックアウトを使用して、配列から選択できるチェックボックスをいくつか作成しました。上記の投稿から取られた作業フィドル:

http://jsfiddle.net/NsCXJ/

果物のIDのみの配列を作成する簡単な方法はありますか?

selectedFruits.select(fruit=>fruit.id);の行に沿って何かをするC#の方が好きです

Javascript/jqueryと同様のことを行うためのメソッド/既製の関数はありますか?または、最も単純なオプションは、リストをループして2番目の配列を作成することですか? JSONでサーバーに配列をポストバックするつもりなので、送信されるデータを最小限にしようとしています。

117
Chris Nevill

はい、 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メソッドを使用することをお勧めします。

何らかの理由でもう一方を使用する場合は、古いブラウザのサポート用に常にポリフィルを追加できます。

いつでもカスタムメソッドを配列プロトタイプに追加できます。

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プロパティをフィルタリングするときにオブジェクトリテラルベースのソリューションを使用し、より複雑なフィルタリングのためにコールバック関数を渡すことです。

ネイティブオブジェクトプロトタイプにメソッドを追加する場合、2つの一般的なヒントでこれを終了します。

  1. 上書きする前に、既存のメソッドの発生を確認します。例:

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

  2. IE8以下をサポートする必要がない場合は、 Object.defineProperty を使用してメソッドを定義し、列挙できないようにします。誰かが配列でfor..inを使用した場合(そもそも間違っています)、列挙可能なプロパティも繰り返します。ただ頭を上げます。

196
Johan

私はそれが遅い答えであることを知っていますが、それは私にとって有用でした!完了するために、$.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; });
32
Stefano Altieri

ノックアウトを使用しているため、ノックアウトユーティリティ関数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;
});

JavascriptでLINQのようなインターフェイスが必要な場合は、 linq.js などのライブラリを使用できます。これは、多くのLINQメソッドへのNiceインターフェイスを提供します。

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

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/

10
July.Tech

linq.js を試すこともできます

linq.js your

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

なります

Enumerable.From(selectedFruits).Select(function (fruit) { return fruit.id;  });
9
Anik Islam Abhi

TsLinq.codeplex.com の下にTypeScript用のLinqライブラリを作成しました。これはプレーンjavascriptにも使用できます。このライブラリは、Linq.jsの2〜3倍高速で、すべてのLinqメソッドの単体テストが含まれています。たぶんあなたはそれをレビューすることができます。

3
Michael Baarz

nderscore.js を見てください。これにより、多くのlinqのような関数が提供されます。あなたが与える例では、マップ関数を使用します。

2
Gruff Bunny

すべてのC#LINQメソッドを実装し、その構文を保存するmanipulaパッケージを試すことができます。 https://github.com/litichevskiydv/manipula

https://www.npmjs.com/package/manipula

サンプルのselectedFruits.select(fruit=>fruit.id);は、manipulaとして次のように実装されます。

Manipula.from(selectedFruits).select(fruit=>fruit.id);
1
razon

Dinqyjs はlinqのような構文を持ち、mapやindexOfなどの関数にポリフィルを提供し、Javascriptで配列を操作するために特別に設計されています。

0
garryp