it-swarm.com.de

Javascript entspricht C # LINQ Select

Folge dieser Frage hier:

Wenn Sie die aktivierte Knockout-Bindung mit einer Liste von Kontrollkästchen verwenden, werden alle Kontrollkästchen aktiviert.

Ich habe mit Knockout einige Kontrollkästchen erstellt, die die Auswahl aus einem Array ermöglichen. Arbeitsgeige von oben genommen:

http://jsfiddle.net/NsCXJ/

Gibt es eine einfache Möglichkeit, ein Array nur der IDs der Früchte zu erstellen?

Ich bin zuhause mit C #, wo ich etwas in der Art von selectedFruits.select(fruit=>fruit.id); machen würde.

Gibt es eine Methode/fertige Funktion, um etwas Ähnliches mit Javascript/jquery zu machen? Oder wäre die einfachste Möglichkeit, die Liste zu durchlaufen und ein zweites Array zu erstellen? Ich beabsichtige, das Array in JSON zurück auf den Server zu stellen, also versuche ich, die gesendeten Daten zu minimieren.

121
Chris Nevill

Ja, Array.map () oder $ .map () macht dasselbe.

//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/

Da array.map in älteren Browsern nicht unterstützt wird, empfehle ich, die jQuery-Methode beizubehalten.

Wenn Sie aus irgendeinem Grund die andere bevorzugen, können Sie jederzeit eine Polyfüllung für die Unterstützung alter Browser hinzufügen.

Sie können dem Array-Prototyp auch jederzeit benutzerdefinierte Methoden hinzufügen:

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

Eine erweiterte Version, die den Funktionskonstruktor verwendet, wenn Sie eine Zeichenfolge übergeben. Vielleicht etwas zum Herumspielen:

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/

Update:

Da dies zu einer so beliebten Antwort geworden ist, füge ich mein where() + firstOrDefault() hinzu. Diese können auch mit dem auf Zeichenfolgen basierenden Funktionskonstruktor-Ansatz (der am schnellsten ist) verwendet werden. Hier ist jedoch ein anderer Ansatz, der ein Objektliteral als Filter verwendet:

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

Verwendung:

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

Hier ist ein jsperf test , um den Funktionskonstruktor mit der Objektliteralgeschwindigkeit zu vergleichen. Wenn Sie sich für Ersteres entscheiden, denken Sie daran, die Zeichenfolgen korrekt zu zitieren.

Ich persönlich bevorzuge es, beim Filtern von 1-2 Eigenschaften die objektliteralbasierten Lösungen zu verwenden und eine Rückruffunktion für eine komplexere Filterung zu übergeben.

Ich werde dies mit zwei allgemeinen Tipps zum Hinzufügen von Methoden zu nativen Objektprototypen beenden:

  1. Prüfen Sie vor dem Überschreiben, ob vorhandene Methoden vorhanden sind, z.

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

  2. Wenn Sie IE8 und höher nicht unterstützen müssen, definieren Sie die Methoden mit Object.defineProperty , um sie nicht aufzählbar zu machen. Wenn jemand for..in Für ein Array verwendet (was an erster Stelle falsch ist), werden auch die aufzählbaren Eigenschaften durchlaufen. Nur ein Kopf hoch.

199
Johan

Ich weiß, es ist eine späte Antwort, aber es war nützlich für mich! Zum Abschluss können Sie mit der Funktion $.grep Die Funktion linq where() emulieren.

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

Da Sie Knockout verwenden, sollten Sie die Knockout-Dienstprogrammfunktion arrayMap() und andere Array-Dienstprogrammfunktionen in Betracht ziehen.

Hier finden Sie eine Auflistung der Array-Dienstprogrammfunktionen und der entsprechenden LINQ-Methoden:

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)

In Ihrem Beispiel könnten Sie also Folgendes tun:

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

Wenn Sie eine LINQ-ähnliche Oberfläche in Javascript benötigen, können Sie eine Bibliothek wie linq.js verwenden, die eine nette Oberfläche für viele der LINQ-Methoden bietet.

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

Der ES6 Weg:

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

auch unter: https://jsfiddle.net/52dpucey/

10
July.Tech

Sie können auch versuchen, linq.js

In linq.js Ihr

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

wird sein

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

Ich habe eine Linq-Bibliothek für TypeScript unter TsLinq.codeplex.com erstellt, die Sie auch für einfaches Javascript verwenden können. Diese Bibliothek ist 2-3 mal schneller als Linq.js und enthält Komponententests für alle Linq-Methoden. Vielleicht könnten Sie das überprüfen.

3
Michael Baarz

Werfen Sie einen Blick auf nderscore.js , das viele linq-ähnliche Funktionen bietet. In dem von Ihnen angegebenen Beispiel würden Sie die Kartenfunktion verwenden.

2
Gruff Bunny

Sie können das Paket manipula ausprobieren, das alle C # LINQ-Methoden implementiert und dessen Syntax speichert: https://github.com/litichevskiydv/manipula

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

Ihr Beispiel selectedFruits.select(fruit=>fruit.id); wird mit manipula as implementiert

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

Dinqyjs hat eine linq-ähnliche Syntax und bietet Polyfüllungen für Funktionen wie map und indexOf und wurde speziell für die Arbeit mit Arrays in Javascript entwickelt.

0
garryp