Javascript équivalent à C # LINQ Select

suite à cette question ici :

utilisation de la reliure contrôlée dans knockout avec une liste de cases à cocher toutes les cases à cocher

j'ai créé quelques cases à cocher en utilisant knockout qui permettent la sélection à partir d'un tableau. violon de travail tiré d'en haut post:

http://jsfiddle.net/NsCXJ /

y a-t-il une façon simple de créer une rangée de pièces D'identité du fruit?

je suis plus à la maison avec C# où je ferais quelque chose comme selectedFruits.select(fruit=>fruit.id);

y a-t-il une méthode/fonction prête à l'emploi pour faire quelque chose de similaire avec javascript/jquery? Ou l'option la plus simple serait-elle de boucler la liste et de créer un second tableau? J'ai l'intention de poster le tableau vers le serveur dans JSON donc j'essaie de minimiser les données envoyées.

102
demandé sur Community 2013-09-21 23:34:47

8 réponses

Oui, "1519100920 Tableau.carte () ou $.map() fait la même chose.

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

depuis array.map n'est pas pris en charge dans les navigateurs plus anciens, je suggère que vous vous en teniez à la méthode jQuery.

si vous préférez l'autre pour une raison quelconque, vous pouvez toujours ajouter un polyfill pour l'ancien support du navigateur.

vous pouvez toujours ajouter des méthodes personnalisées au prototype du tableau aussi bien:

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

une version étendue qui utilise le constructeur de fonction si vous passez une chaîne. Quelque chose à jouer avec peut-être:

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/

mise à jour:

depuis qu'il est devenu si populaire réponse, j'ajoute similaire mon where() + firstOrDefault() . Ceux-ci pourraient également être utilisés avec l'approche du constructeur de fonctions basé sur la chaîne de caractères (qui est la plus rapide), mais voici une autre approche utilisant un objet littéral comme filtre:

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

Utilisation:

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

voici un test jsperf pour comparer la fonction constructeur vs objet Vitesse littérale. Si vous décidez d'utiliser l'ancien, gardez à l'esprit pour citer les chaînes correctement.

Ma préférence personnelle est d'utiliser l'objet literal based solutions lors du filtrage des propriétés 1-2, et passer une fonction de rappel pour un filtrage plus complexe.

je terminerai ceci avec 2 Conseils généraux lors de l'ajout de méthodes à des prototypes d'objets natifs:

  1. vérifier l'occurrence des méthodes existantes avant d'écrire p. ex.:

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

  2. si vous n'avez pas besoin de supporter IE8 et ci-dessous, définissez les méthodes en utilisant L'objet .defineProperty pour les rendre non-énumérable. Si quelqu'un a utilisé for..in sur un tableau (ce qui est faux, en premier lieu,) ils itérer les propriétés énumérables. Juste un heads-up.

171
répondu Johan 2018-01-31 18:58:31

je sais que c'est une réponse tardive mais elle m'a été utile! Juste pour compléter, en utilisant la fonction $.grep vous pouvez émuler la 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; });
30
répondu Stefano Altieri 2014-05-15 14:35:10

puisque vous utilisez knockout, vous devriez considérer l'utilisation de la fonction d'utilité de knockout arrayMap() et ses autres fonctions d'utilité de tableau.

Voici une liste des fonctions Utilitaires du tableau et leurs méthodes LINQ équivalentes:

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)

donc ce que vous pourriez faire dans votre exemple est ceci:

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

si vous voulez une interface de type LINQ en javascript, vous pouvez utiliser une bibliothèque telle que linq.js qui offre une interface agréable à beaucoup de méthodes LINQ.

var mapped = Enumerable.From(selectedFruits)
    .Select("$.id") // 1 of 3 different ways to specify a selector function
    .ToArray();
13
répondu Jeff Mercado 2013-09-21 22:12:09

vous pouvez également essayer linq.js

linq.js votre

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

sera

Enumerable.From(selectedFruits).Select(function (fruit) { return fruit.id;  });
9
répondu Anik Islam Abhi 2016-01-07 02:11:54

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

aussi à: https://jsfiddle.net/52dpucey /

7
répondu July.Tech 2016-12-19 15:41:28

jetez un oeil à underscore.js qui fournit beaucoup de linq comme des fonctions. Dans l'exemple que vous donnez, vous utilisez la fonction map.

2
répondu Gruff Bunny 2013-09-21 19:47:19

j'ai construit une bibliothèque Linq pour dactylographier sous TsLinq.codeplex.com que vous pouvez utiliser pour JavaScript simple aussi. Cette bibliothèque est 2 à 3 fois plus rapide que Linq.js et contient des tests unitaires pour toutes les méthodes Linq. Peut-être que vous pourriez examiner.

2
répondu Michael Baarz 2014-05-15 14:13:30

Dinqyjs a une syntaxe linq-like et fournit des polyfills pour des fonctions comme la carte et l'indexOf, et a été conçu spécifiquement pour travailler avec des tableaux en Javascript.

0
répondu garryp 2015-01-02 00:33:33