Javascript Setara dengan C # LINQ Pilih

137

Mengikuti pertanyaan ini di sini:

Menggunakan sistem penjilidan mengikat yang dicentang dengan daftar kotak centang memeriksa semua kotak centang

Saya telah membuat beberapa kotak centang menggunakan sistem gugur yang memungkinkan pemilihan dari sebuah array. biola kerja diambil dari pos di atas:

http://jsfiddle.net/NsCXJ/

Apakah ada cara sederhana untuk membuat array hanya ID buah?

Saya lebih di rumah dengan C # di mana saya akan melakukan sesuatu di sepanjang baris selectedFruits.select(fruit=>fruit.id);

Apakah ada beberapa metode / fungsi siap pakai untuk melakukan sesuatu yang mirip dengan javascript / jquery? Atau akankah pilihan paling sederhana adalah untuk mengulang daftar dan membuat array kedua? Saya bermaksud memposting array kembali ke server di JSON jadi saya mencoba untuk meminimalkan data yang dikirim.

Chris Nevill
sumber

Jawaban:

227

Ya, Array.map () atau $ .map () melakukan hal yang sama.

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

Karena array.map tidak didukung di browser lama, saya sarankan Anda tetap menggunakan metode jQuery.

Jika Anda lebih suka yang lain karena alasan tertentu Anda selalu bisa menambahkan polyfill untuk dukungan browser lama.

Anda selalu dapat menambahkan metode khusus ke prototipe array:

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

Versi diperpanjang yang menggunakan konstruktor fungsi jika Anda melewatkan string. Sesuatu untuk dimainkan mungkin:

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/

Memperbarui:

Karena ini telah menjadi jawaban yang begitu populer, saya menambahkan where()+ saya yang serupa firstOrDefault(). Ini juga dapat digunakan dengan pendekatan konstruktor fungsi berbasis string (yang tercepat), tetapi di sini ada pendekatan lain menggunakan objek literal sebagai filter:

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

Pemakaian:

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

Berikut adalah tes jsperf untuk membandingkan fungsi constructor vs kecepatan literal objek. Jika Anda memutuskan untuk menggunakan yang pertama, ingatlah untuk mengutip string dengan benar.

Preferensi pribadi saya adalah menggunakan solusi berbasis objek objek saat memfilter properti 1-2, dan meneruskan fungsi panggilan balik untuk pemfilteran yang lebih kompleks.

Saya akan mengakhiri ini dengan 2 tips umum ketika menambahkan metode ke prototipe objek asli:

  1. Periksa kemunculan metode yang ada sebelum menimpa misalnya:

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

  2. Jika Anda tidak perlu mendukung IE8 dan di bawah ini, tentukan metode menggunakan Object.defineProperty untuk membuatnya tidak dapat dihitung. Jika seseorang menggunakan for..inarray (yang salah di tempat pertama) mereka akan mengulangi properti enumerable juga. Hanya kepala.

Johan
sumber
1
@ ChrisNevill Saya menambahkan versi string juga jika Anda tertarik
Johan
@MUlferts Tangkapan bagus, diperbarui :). Saat ini saya akan menyarankan menggunakan lodash untuk tugas-tugas semacam ini. Mereka mengekspos antarmuka yang sama dengan kode di atas
Johan
Untuk mendukung yang bisa diobservasi:return typeof item[property] === 'function' ? item[property]() === filter[property] : item[property] === filter[property];
Linus Caldwell
@LinusCaldwell Sudah lama sejak saya menggunakan KO, tapi bagaimana dengan sesuatu seperti return ko.unwrap(item[property]) === filter[property]?
Johan
Yah, saya sebutkan KO, tapi tentu saja ini akan mencakup semua properti yang berfungsi tanpa parameter yang diperlukan. Selain itu, mengapa orang mematahkan gaya generik kode cantik Anda?
Linus Caldwell
33

Saya tahu ini adalah jawaban yang terlambat tetapi itu berguna bagi saya! Untuk melengkapi, menggunakan $.grepfungsi Anda dapat meniru 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; });
Stefano Altieri
sumber
itulah yang saya inginkan..tapi apa yang lebih baik di antara jawaban Anda dan Enumerable.From (selectedFruits). Pilih (fungsi (buah) {return fruit.id;});
Bharat
15

Karena Anda menggunakan sistem KO, Anda harus mempertimbangkan untuk menggunakan fungsi utilitas sistem KO arrayMap()dan itu adalah fungsi utilitas array lainnya.

Berikut daftar fungsi utilitas array dan metode LINQ yang setara:

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)

Jadi yang dapat Anda lakukan dalam contoh Anda adalah ini:

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

Jika Anda ingin antarmuka seperti LINQ dalam javascript, Anda bisa menggunakan perpustakaan seperti linq.js yang menawarkan antarmuka yang bagus untuk banyak metode LINQ.

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

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

juga di: https://jsfiddle.net/52dpucey/

July.Tech
sumber
Sangat dihargai. Saya baru saja masuk ke ES6 sehingga ini bisa berguna!
Chris Nevill
10

Anda juga bisa mencoba linq.js

Di linq.jsAnda

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

akan

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

Saya telah membangun pustaka Linq untuk TypeScript di bawah TsLinq.codeplex.com yang dapat Anda gunakan untuk javascript biasa juga. Pustaka itu 2-3 kali lebih cepat dari Linq.js dan berisi tes unit untuk semua metode Linq. Mungkin Anda bisa mengulasnya.

Michael Baarz
sumber
2

Mengintip underscore.js yang menyediakan banyak fungsi seperti linq. Dalam contoh yang Anda berikan, Anda akan menggunakan fungsi peta.

Gruff Bunny
sumber
1
Jika seseorang ingin tahu bagaimana mereka membandingkan saya membuat posting blog yang menjelaskan perbedaan antara lebih dari 15 fungsi LINQ / underscore.js paling populer: vladopandzic.com/javascript/comparing-underscore-js-with-linq
Vlado Pandžić
0

Dinqyjs memiliki sintaks seperti linq dan menyediakan polyfill untuk fungsi-fungsi seperti map dan indexOf, dan telah dirancang khusus untuk bekerja dengan array dalam Javascript.

garryp
sumber
0

Lihatlah fasih , ia mendukung hampir semua yang dilakukan LINQ dan didasarkan pada iterables - sehingga bekerja dengan peta, fungsi generator, array, semuanya dapat diubah.

kataik
sumber
-1

Saya menjawab judul pertanyaan daripada pertanyaan awal yang lebih spesifik.

Dengan fitur baru Javascript seperti iterators dan fungsi generator dan objek, sesuatu seperti LINQ untuk Javascript menjadi mungkin. Perhatikan bahwa linq.js, misalnya, menggunakan pendekatan yang sama sekali berbeda, menggunakan ekspresi reguler, mungkin untuk mengatasi kurangnya dukungan dalam bahasa pada saat itu.

Dengan itu, saya telah menulis pustaka LINQ untuk Javascript dan Anda dapat menemukannya di https://github.com/Siderite/LInQer . Komentar dan diskusi di https://siderite.dev/blog/linq-in-javascript-linqer .

Dari jawaban sebelumnya, tampaknya hanya Manipula yang diharapkan dari port LINQ di Javascript.

Siderite Zackwehdex
sumber