1. ホーム
  2. javascript

[解決済み] C#のLINQセレクトに相当するJavascript

2022-04-26 16:09:15

質問

この質問に続きます。

<ブロッククオート

チェックボックスのリストでknockoutのcheckedバインディングを使用すると、すべてのチェックボックスがチェックされます。

ノックアウトで配列から選択できるチェックボックスをいくつか作りました。 上の記事から引用しています。

http://jsfiddle.net/NsCXJ/

果物のIDだけを配列にする簡単な方法はありますか?

私はC#の方が得意で、次のようなことをします。 selectedFruits.select(fruit=>fruit.id);

javascript/jqueryで同様のことを行う方法/既製の関数はありますか? それとも、一番簡単な方法は、リストをループして2番目の配列を作ることでしょうか? 私はJSONでサーバーに配列を戻すつもりなので、送信されるデータを最小限にしようとしています。

どのように解決しますか?

はい。 配列.マップ() または $.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テスト 関数コンストラクタとオブジェクトリテラルの速度を比較するためです。前者を使用する場合は、文字列を正しく引用することに注意してください。

個人的な好みとしては、1~2個のプロパティをフィルタリングする場合はオブジェクトリテラルベースのソリューションを使用し、より複雑なフィルタリングを行う場合はコールバック関数を渡します。

最後に、ネイティブ・オブジェクトのプロトタイプにメソッドを追加する際の一般的なヒントを2つ挙げておきます。

  1. 上書きする前に、既存のメソッドの出現を確認する 例.

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

  2. IE8以下に対応する必要がない場合、メソッドの定義は Object.defineProperty を使用して、それらを列挙できないようにします。もし誰かが for..in を配列に適用することは(そもそも間違っていますが)。 は、列挙可能なプロパティも同様に反復することになります。一応、注意事項です。