Javascript, эквивалентный C# LINQ Select
после этого вопроса здесь:
используя отмеченную привязку в нокауте со списком флажков, проверяет все флажки
Я создал некоторые флажки, используя нокаут, которые позволяют выбирать из массива. рабочая скрипка взята сверху поста:
есть ли простой способ создания массива только фруктов Идентификаторы?
Я больше дома с C#, где я бы сделал что-то вроде selectedFruits.select(fruit=>fruit.id);
есть ли какой-то метод/готовая функция для выполнения чего-то подобного с javascript/jquery? Или самый простой вариант-перебрать список и создать второй массив? Я намерен опубликовать массив обратно на сервер в JSON, поэтому пытаюсь минимизировать отправленные данные.
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);
С массива.карта не поддерживается в старых браузерах, я предлагаю вам придерживаться метод jQuery.
если вы предпочитаете другой по какой-то причине, вы всегда можете добавить polyfill для старой поддержки браузера.
вы всегда можете добавлять пользовательские методы в прототип массива хорошо:
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'));
обновление:
так как это стало таким популярным ответом, я добавляю похожие мои 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 общими советами при добавлении методов к прототипам собственных объектов:
-
проверьте наличие существующих методов перед перезаписью, например:
if(!Array.prototype.where) { Array.prototype.where = ...
Если вам не нужно поддерживать 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();
кстати на 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);
}
посмотреть подчеркивания.js который предоставляет множество функций linq like. В приведенном примере вы будете использовать функцию map.
Я построил библиотеку Linq для TypeScript под TsLinq.codeplex.com что вы можете использовать для простого javascript тоже. Эта библиотека в 2-3 раза быстрее, чем Linq.JS и содержит модульные тесты для всех методов Linq. Может быть, вы могли бы рассмотреть это.
Dinqyjs имеет синтаксис linq-like и предоставляет поля для таких функций, как map и indexOf, и был разработан специально для работы с массивами в Javascript.