JavaScript-эквивалентом в C# LINQ для выбора


после этого вопроса здесь:

использование проверенной привязки в нокауте со списком флажков проверяет все флажки

Я создал некоторые флажки с помощью нокаута, которые позволяют выбирать из массива. рабочая скрипка, взятая сверху поста:

http://jsfiddle.net/NsCXJ/

есть ли простой способ создания массива только фруктов Документы?

Я больше дома с C#, где я бы сделал что-то вроде selectedFruits.select(fruit=>fruit.id);

есть ли какой-то метод/готовая функция для выполнения чего-то подобного с javascript/jquery? Или самый простой вариант-перебрать список и создать второй массив? Я намерен отправить массив обратно на сервер в JSON, поэтому пытаюсь свести к минимуму отправленные данные.

8 102

8 ответов:

да массив.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/

С массива.карта не поддерживается в старых браузерах, я предлагаю вам придерживаться метод 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 и ниже, определите методы с помощью

Я знаю, что это поздний ответ, но это было полезно для меня! Просто для завершения, используя $.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; });

так как вы используете нокаут, вы должны рассмотреть возможность использования функции нокаут утилита 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;
});

если вы хотите LINQ как интерфейс в javascript, вы можете использовать библиотеку, такую как linq.js который предлагает хороший интерфейс для многих из LINQ методы.

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

вы также можете попробовать linq.js

на linq.js код

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

будет

Enumerable.From(selectedFruits).Select(function (fruit) { return fruit.id;  });

путь 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/

посмотреть подчеркивания.js что обеспечивает много линк как функции. В приведенном примере вы будете использовать функцию map.

Я построил библиотеку Linq для TypeScript под TsLinq.codeplex.com что вы можете использовать для простого javascript тоже. Эта библиотека в 2-3 раза быстрее, чем Linq.js и содержит модульные тесты для всех методов Linq. Может быть, вы могли бы рассмотреть это.

Dinqyjs имеет LINQ-подобный синтаксис и предоставляет полифиллы для таких функций, как map и indexOf, и был разработан специально для работы с массивами в Javascript.