Javascript ile Eşdeğer C # LINQ Seçin


137

Bu soruyu burada takip ederek:

Nakavtta işaretli bağlayıcıyı bir onay kutuları listesiyle kullanmak tüm onay kutularını kontrol eder

Bir diziden seçime izin veren nakavt kullanarak bazı onay kutuları oluşturdum. yukarıdan alınan çalışma keman:

http://jsfiddle.net/NsCXJ/

Sadece meyve kimlikleri dizisi oluşturmanın basit bir yolu var mı?

C # ile daha fazla evdeyim. selectedFruits.select(fruit=>fruit.id);

Javascript / jquery ile benzer bir şey yapmak için bazı yöntem / hazır fonksiyon var mı? Ya da en basit seçenek listede dolaşıp ikinci bir dizi oluşturmak mı? JSON sunucuya geri dizi göndermek niyetinde çok gönderilen veri en aza indirmek için çalışıyorum.

Yanıtlar:


227

Evet, Array.map () veya $ .map () aynı şeyi yapar.

//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 eski tarayıcılarda desteklenmediğinden, jQuery yöntemine bağlı kalmanızı öneririm.

Diğerini bir nedenle tercih ederseniz, eski tarayıcı desteği için her zaman bir çoklu dolgu ekleyebilirsiniz.

Dizi prototipine her zaman özel yöntemler de ekleyebilirsiniz:

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

Bir dize iletirseniz işlev yapıcısını kullanan genişletilmiş bir sürüm. Belki de oynayabileceğiniz bir şey:

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/

Güncelleme:

Bu çok popüler bir cevap haline geldiğinden, where()+ 'ya benzer bir şey ekliyorum firstOrDefault(). Bunlar aynı zamanda (en hızlı olan) dize tabanlı işlev yapıcı yaklaşımı ile de kullanılabilir, ancak burada bir nesne değişmezini filtre olarak kullanan başka bir yaklaşım vardır:

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

Kullanımı:

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

Fonksiyon yapıcısı ile nesne değişmez hızını karşılaştırmak için bir jsperf testi . Birincisini kullanmaya karar verirseniz, dizeleri doğru şekilde alıntılamayı unutmayın.

Kişisel tercihim 1-2 özelliğe filtre uygularken nesne tabanlı çözümleri kullanmak ve daha karmaşık filtreleme için geri arama işlevini iletmektir.

Yerel nesne prototiplerine yöntem eklerken bunu 2 genel ipucu ile bitireceğim:

  1. Üzerine yazmadan önce mevcut yöntemlerin olup olmadığını kontrol edin örn.

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

  2. IE8 ve aşağısını desteklemeniz gerekmiyorsa , numaralandırılamaz hale getirmek için Object.defineProperty'yi kullanarak yöntemleri tanımlayın . Birisi for..inbir dizi (ilk etapta yanlış) kullanılırsa onlar da numaralandırılabilir özellikleri yineleyecektir. Sadece aklınızda bulunsun.


1
@ChrisNevill İlgilenmeniz durumunda bir dize sürümü de ekledim
Johan

@MUlferts İyi yakalama, güncellendi :). Bugünlerde bu tür görevler için lodash kullanmanızı öneririm. Yukarıdaki kodla aynı arayüzü ortaya
Johan

Nakavt gözlemlenebilirlerini desteklemek için:return typeof item[property] === 'function' ? item[property]() === filter[property] : item[property] === filter[property];
Linus Caldwell

@LinusCaldwell Nakavt kullandığımdan bu yana uzun zaman geçti, ama nasıl bir şey return ko.unwrap(item[property]) === filter[property]?
Johan

Nakavttan bahsettim, ama elbette bu gerekli parametreler olmadan işlev gören tüm özellikleri kapsayacaktı. Ayrıca, neden güzel kodunuzun jenerik tarzını kıralım ki?
Linus Caldwell

33

Geç bir cevap olduğunu biliyorum ama benim için yararlı oldu! Sadece tamamlamak için, $.grepfonksiyonu kullanarak linq taklit edebilirsinizwhere() .

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

istediğim budur ... ama cevabınız ile Enumerable arasında daha iyi olan nedir.
Bharat

15

Nakavt kullandığınız için nakavt yardımcı işlevini kullanmayı düşünmelisiniz arrayMap() ve diğer dizi yardımcı işlevlerini .

Dizi yardımcı programı işlevlerinin ve eşdeğer LINQ yöntemlerinin listesi:

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)

Örneğinizde yapabileceğiniz şey şudur:

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

Javascript içinde LINQ benzeri bir arayüz istiyorsanız, linq.js gibi birçok LINQ yöntemine hoş bir arayüz sunan bir kütüphane kullanabilirsiniz .

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

14

ES6 yolu:

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

ayrıca: https://jsfiddle.net/52dpucey/


Çok takdir etmek. Sadece ES6'ya giriyorum, bu yüzden bu kullanışlı olabilir!
Chris Nevill

10

Ayrıca deneyebilirsiniz linq.js

In linq.jssenin

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

olacak

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

4

Ben de düz javascript için kullanabileceğiniz TsLinq.codeplex.com altında TypeScript için bir Linq kütüphanesi inşa var . Bu kütüphane Linq.js'den 2-3 kat daha hızlıdır ve tüm Linq yöntemleri için birim testleri içerir. Belki bunu gözden geçirebilirsin.




0

Dinqyjs , linq benzeri bir sözdizimine sahiptir ve map ve indexOf gibi işlevler için çoklu dolgular sağlar ve özellikle Javascript'teki dizilerle çalışmak üzere tasarlanmıştır.


0

Akıcı bir şekilde göz atın , LINQ'nun neredeyse her şeyi destekler ve yinelemelere dayanır - böylece haritalar, jeneratör işlevleri, diziler, yinelenebilir her şeyle çalışır.



-1

Daha spesifik olan orijinal sorudan ziyade sorunun başlığını cevaplıyorum.

Javascript'in yineleyiciler ve jeneratör işlevleri ve nesneleri gibi yeni özellikleri ile LINQ for Javascript gibi bir şey mümkün olur. Örneğin, linq.js'nin, o sırada dilde destek eksikliğinin üstesinden gelmek için düzenli ifadeler kullanarak tamamen farklı bir yaklaşım kullandığını unutmayın.

Bununla birlikte, Javascript için bir LINQ kütüphanesi yazdım ve bunu https://github.com/Siderite/LInQer adresinde bulabilirsiniz . Https://siderite.dev/blog/linq-in-javascript-linqer adresindeki yorumlar ve tartışma .

Önceki yanıtlardan, Javascript'teki bir LINQ portundan beklediğiniz şey sadece Manipula gibi görünüyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.