C#LINQ Selectと同等のJavascript


137

ここでこの質問に従ってください:

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

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

http://jsfiddle.net/NsCXJ/

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

私はC#に慣れているので、 selectedFruits.select(fruit=>fruit.id);

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

回答:


227

はい、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/

更新:

これは非常に人気のある回答になっているため、同様のmy 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配列を使用した場合(そもそも間違っています)、列挙可能なプロパティも繰り返し処理します。頭を上げただけです。


1
@ChrisNevill興味がある場合に備えて、文字列バージョンも追加しました
Johan

@MUlfertsグッドキャッチ、更新:)。最近では、これらの種類のタスクにはlodashを使用することをお勧めします。彼らは上記のコードと同じインターフェイスを公開しています
Johan

観測をノックアウトサポートするために:return typeof item[property] === 'function' ? item[property]() === filter[property] : item[property] === filter[property];
ライナス・コールドウェル

@LinusCaldwellノックアウトを使って久しぶりreturn ko.unwrap(item[property]) === filter[property]ですが、どうですか?
ヨハン

さて、私はノックアウトについて述べましたが、もちろんこれは必要なパラメータなしの関数であるすべてのプロパティをカバーします。その上、なぜあなたはあなたの美しいコードの一般的なスタイルを壊すのですか?
Linus Caldwell

33

私はそれが遅い答えであることを知っていますが、それは私にとって役に立ちました!完了するだけで、$.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; });

それが私が欲しいものです。しかし、あなたの答えとEnumerable.From(selectedFruits).Select(function(fruit){return fruit.id;});の間のより良いものは何ですか?
Bharat

15

ノックアウトを使用しているため、ノックアウトユーティリティ関数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メソッドへの優れたインターフェイスを提供できます。

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

14

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/


とても有難い。ES6に入るので、これは便利かもしれません!
Chris Nevill、2016


4

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




0

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


0

fluentを見てください。これは、LINQが実行するほぼすべての処理をサポートし、反復可能オブジェクトに基づいています。そのため、マップ、ジェネレーター関数、配列など、反復可能なすべてのものが動作します。



-1

より具体的な元の質問ではなく、質問のタイトルに回答しています。

イテレーターやジェネレーターの関数やオブジェクトなどのJavascriptの新機能により、LINQ for JavaScriptのようなものが可能になります。たとえば、linq.jsは、正規表現を使用した完全に異なるアプローチを使用しており、おそらくその時点での言語のサポートの欠如を克服するためのものです。

そうは言っても、私はJavascript用のLINQライブラリを作成しました。https://github.com/Siderite/LInQerで見つけることができますhttps://siderite.dev/blog/linq-in-javascript-linqerでのコメントとディスカッション

以前の回答から、マニピュラだけがJavascriptのLINQポートから期待されるものであるように思われます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.