Javascript เทียบเท่ากับ C # LINQ Select


142

ติดตามคำถามนี้ได้ที่นี่:

การใช้การเชื่อมโยงที่เลือกไว้ในสิ่งที่น่าพิศวงพร้อมรายการช่องทำเครื่องหมายจะตรวจสอบช่องทำเครื่องหมายทั้งหมด

ฉันได้สร้างช่องทำเครื่องหมายโดยใช้สิ่งที่น่าพิศวงที่อนุญาตให้เลือกจากอาร์เรย์ การทำงานที่นำมาจากโพสต์ด้านบน:

http://jsfiddle.net/NsCXJ/

มีวิธีง่ายๆในการสร้างอาร์เรย์ของ ID ของผลไม้หรือไม่?

ฉันอยู่บ้านมากขึ้นด้วย C # ที่ซึ่งฉันจะทำอะไรบางอย่างตามแนวของ selectedFruits.select(fruit=>fruit.id);

มีวิธีการ / ฟังก์ชันสำเร็จรูปสำหรับการทำสิ่งที่คล้ายกันกับ javascript / jquery หรือไม่? หรือตัวเลือกที่ง่ายที่สุดคือการวนซ้ำรายการและสร้างอาร์เรย์ที่สอง? ฉันตั้งใจจะโพสต์อาร์เรย์กลับไปที่เซิร์ฟเวอร์ใน JSON ดังนั้นฉันจึงพยายามย่อขนาดข้อมูลที่ส่ง

คำตอบ:


230

ใช่Array.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/

เนื่องจากไม่รองรับ array.map ในเบราว์เซอร์รุ่นเก่าฉันขอแนะนำให้คุณใช้วิธี 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'));

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 หรือต่ำกว่าให้กำหนดวิธีการโดยใช้Object.definePropertyเพื่อให้ไม่สามารถนับได้ หากมีคนใช้for..inอาร์เรย์ (ซึ่งผิดตั้งแต่แรก) พวกเขาจะทำซ้ำคุณสมบัติที่แจกแจงได้เช่นกัน เพียงแค่หัวขึ้น


1
@ChrisNevill ฉันได้เพิ่มเวอร์ชันสตริงเช่นกันในกรณีที่คุณถูกบุกรุก
โยฮัน

@MUlferts จับดีปรับปรุง :). วันนี้ฉันขอแนะนำให้ใช้ lodash สำหรับงานประเภทนี้ พวกเขาเปิดเผยอินเทอร์เฟซเดียวกันกับโค้ดด้านบน
Johan

เพื่อสนับสนุนการสังเกตการณ์ที่น่าพิศวง:return typeof item[property] === 'function' ? item[property]() === filter[property] : item[property] === filter[property];
Linus Caldwell

@LinusCaldwell เป็นเวลานานแล้วที่ฉันใช้สิ่งที่น่าพิศวง แต่สิ่งที่เป็นreturn ko.unwrap(item[property]) === filter[property]อย่างไร?
Johan

ฉันพูดถึงสิ่งที่น่าพิศวง แต่แน่นอนว่าสิ่งนี้จะครอบคลุมคุณสมบัติทั้งหมดซึ่งเป็นฟังก์ชันที่ไม่มีพารามิเตอร์ที่จำเป็น นอกจากนี้ทำไมเราถึงทำลายรูปแบบทั่วไปของรหัสที่สวยงามของคุณ?
Linus Caldwell

33

ฉันรู้ว่ามันเป็นคำตอบที่ล่าช้า แต่มันมีประโยชน์สำหรับฉัน! เพียงแค่ให้เสร็จสมบูรณ์โดยใช้$.grepฟังก์ชั่นที่คุณสามารถเลียนแบบ where()LINQ

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

นั่นคือสิ่งที่ฉันต้องการ.. แต่สิ่งที่ดีกว่าระหว่างคำตอบของคุณกับ Enumerable จาก (selectedFruits) เลือก (function (fruit) {return fruit.id;});
Bharat

15

เนื่องจากคุณกำลังใช้สิ่งที่น่าพิศวงคุณควรพิจารณาใช้ฟังก์ชันยูทิลิตี้ที่น่าพิศวง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 เหมือนกับอินเทอร์เฟซในจาวาสคริปต์คุณสามารถใช้ไลบรารีเช่นlinq.jsซึ่งมีอินเทอร์เฟซที่ดีสำหรับวิธีการ LINQ หลายวิธี

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

15

วิธี 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/


ชื่นชมมาก ฉันเพิ่งเข้าสู่ ES6 ดังนั้นสิ่งนี้จึงมีประโยชน์!
Chris Nevill


4

ฉันได้สร้างไลบรารี Linq สำหรับ TypeScript ภายใต้TsLinq.codeplex.comซึ่งคุณสามารถใช้กับจาวาสคริปต์ธรรมดาได้เช่นกัน ไลบรารีนั้นเร็วกว่า Linq.js 2-3 เท่าและมีการทดสอบหน่วยสำหรับวิธี Linq ทั้งหมด บางทีคุณอาจจะทบทวนเรื่องนั้น


2

ดูที่underscore.jsซึ่งมีฟังก์ชันเหมือน linq มากมาย ในตัวอย่างที่คุณให้คุณจะใช้ฟังก์ชันแผนที่


1
หากมีใครอยากรู้ว่าพวกเขาเปรียบเทียบฉันทำบล็อกโพสต์อย่างไรซึ่งอธิบายความแตกต่างระหว่างฟังก์ชัน LINQ / underscore.js ที่เป็นที่นิยมมากที่สุดมากกว่า 15 รายการ: vladopandzic.com/javascript/comparing-underscore-js-with-linq
Vlado Pandžić

1

คุณสามารถลองใช้manipulaแพ็คเกจซึ่งใช้วิธีการ C # LINQ ทั้งหมดและบันทึกไวยากรณ์ได้: https://github.com/litichevskiydv/manipula

https://www.npmjs.com/package/manipula

ตัวอย่างของคุณselectedFruits.select(fruit=>fruit.id); จะถูกนำไปใช้กับ manipula as

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

0

Dinqyjsมีไวยากรณ์เหมือน linq และมี polyfills สำหรับฟังก์ชันต่างๆเช่น map และ indexOf และได้รับการออกแบบมาโดยเฉพาะสำหรับการทำงานกับอาร์เรย์ใน Javascript


0

ลองดูอย่างคล่องแคล่วมันรองรับเกือบทุกอย่างที่ LINQ ทำและอิงตามการเล่นซ้ำดังนั้นมันจึงทำงานร่วมกับแผนที่ฟังก์ชันตัวสร้างอาร์เรย์ทุกอย่างที่ทำซ้ำได้


0

Selectอะนาล็อกC # ที่คล้ายกันมากที่สุดจะเป็นmapฟังก์ชัน เพียงใช้:

var ids = selectedFruits.map(fruit => fruit.id);

เพื่อเลือกรหัสทั้งหมดจากselectedFruitsอาร์เรย์

ไม่ต้องการการอ้างอิงภายนอกใด ๆ เพียงแค่ JavaScript บริสุทธิ์ คุณสามารถดูmapเอกสารได้ที่นี่: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map


-1

ฉันกำลังตอบชื่อคำถามแทนที่จะเป็นคำถามเดิมซึ่งเจาะจงมากขึ้น

ด้วยคุณสมบัติใหม่ของ Javascript เช่นตัวทำซ้ำและฟังก์ชันตัวสร้างและวัตถุสิ่งต่างๆเช่น LINQ สำหรับ Javascript จะเป็นไปได้ โปรดทราบว่า linq.js ใช้วิธีการที่แตกต่างไปจากเดิมอย่างสิ้นเชิงโดยใช้นิพจน์ทั่วไปอาจเพื่อเอาชนะการขาดการสนับสนุนในภาษาในขณะนั้น

กับที่ถูกกล่าวว่าผมเคยเขียนห้องสมุด LINQ สำหรับ Javascript และคุณสามารถค้นหาได้ที่https://github.com/Siderite/LInQer ความคิดเห็นและอภิปรายที่https://siderite.dev/blog/linq-in-javascript-linqer

จากคำตอบก่อนหน้านี้ Manipula เท่านั้นที่น่าจะเป็นสิ่งที่คาดหวังจากพอร์ต LINQ ใน Javascript

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.