ความแตกต่างระหว่าง Select และ ConvertAll ใน C #


117

ฉันมีรายการ:

List<int> list = new List<int> { 1, 2, 3, 4, 5 };

ฉันต้องการใช้การเปลี่ยนแปลงบางอย่างกับองค์ประกอบของรายการของฉัน ฉันทำได้สองวิธี:

List<int> list1 = list.Select(x => 2 * x).ToList();
List<int> list2 = list.ConvertAll(x => 2 * x).ToList();

สองทางนี้ต่างกันอย่างไร?


16
คุณไม่จำเป็นต้อง. toList () หลัง ConvertAll ()
Gleno

ไม่เคยได้ยิน ConvertAll มาทำความรู้จักกับสิ่งใหม่ ๆ วันนี้
Amit Bisht

คำตอบ:


117

Selectเป็นวิธีการขยาย LINQ และใช้ได้กับIEnumerable<T>วัตถุทั้งหมดในขณะที่ConvertAllใช้งานโดยList<T>ไฟล์. ConvertAllวิธีการที่มีอยู่ตั้งแต่ NET 2.0 ในขณะที่ได้รับการแนะนำ LINQ กับ 3.5

คุณควรสนับสนุนSelectมากกว่าConvertAllที่ทำงานสำหรับชนิดของรายการใด ๆ แต่พวกเขาทำเช่นเดียวกันโดยทั่วไป


7
แล้วการแสดงล่ะ? ถ้าฉันมีรายการการใช้ ConvertAll หรือ Select จะมีประสิทธิภาพมากกว่ากัน?
Nicolas

@Nicolas: เวลาในการดำเนินการทั้งหมดใกล้เคียงกัน แต่ทำการประมวลผลต่างกันเพื่อให้เหมาะสมกับสถานการณ์ต่างๆ ฉันเพิ่มบางส่วนเกี่ยวกับเรื่องนี้ในคำตอบของฉัน
Guffa

3
คุณไม่สามารถเปรียบเทียบและSelect ConvertAllในอดีตจะเลือกทุกรายการตามลำดับและคุณมีอิสระที่จะทำอะไรก็ได้ที่คุณต้องการ หลังมีเจตนาชัดเจนคือแปลงรายการนี้เป็นอย่างอื่น
Tim Schmelter

1
ในทางกลับกันคลาส List <T> มีหลายวิธีที่มีการจับคู่เกือบทุกประการใน LINQ มีอยู่ -> ใด ๆ ค้นหา -> อันดับแรก FindAll -> ที่ไหน FindLast -> ล่าสุด TrueForAll -> ทั้งหมด
Mikal Schacht Jensen

ความแตกต่างระหว่าง ConvertAll และ Select คือ ConvertAll จะจัดสรรขนาดของรายการก่อนส่งมอบ สำหรับลำดับขนาดใหญ่สิ่งนี้จะสร้างความแตกต่างด้านประสิทธิภาพ ดังนั้นหากประสิทธิภาพคือเป้าหมายของคุณให้ใช้ ConvertAll หากประสิทธิภาพไม่น่ากังวลให้ใช้ Select เนื่องจากเป็นภาษาที่ใช้สำนวนมากขึ้นและบอกว่าประสิทธิภาพของผู้อ่านในอนาคตไม่น่ากังวล
Durdsoft

82

ConvertAllไม่ใช่ส่วนขยาย แต่เป็นวิธีการในคลาสรายการ คุณไม่จำเป็นต้องเรียกToListใช้ผลลัพธ์เนื่องจากเป็นรายการอยู่แล้ว:

List<int> list2 = list.ConvertAll(x => 2 * x);

ดังนั้นความแตกต่างคือConvertAllวิธีนี้สามารถใช้ได้กับรายการเท่านั้นและจะส่งคืนรายการ Selectวิธีการที่สามารถใช้กับคอลเลกชันใด ๆ ที่ใช้อินเตอร์เฟซและจะส่งกลับIEnumerable<T>IEnumerable<T>

นอกจากนี้ยังทำการประมวลผลที่แตกต่างกันดังนั้นจึงมีจุดแข็งในสถานการณ์ที่แตกต่างกัน ConvertAllวิธีการวิ่งผ่านรายการและสร้างรายการใหม่ในหนึ่งไปในขณะที่Selectวิธีการใช้การดำเนินการขี้เกียจและมีเพียงการประมวลผลรายการตามที่คุณต้องการ หากคุณไม่ต้องการสิ่งของทั้งหมดSelectวิธีนี้จะมีประสิทธิภาพมากขึ้น ในทางกลับกันเมื่อConvertAllคืนรายการแล้วคุณไม่จำเป็นต้องเก็บรายชื่อเดิมไว้


โดยทั่วไปแล้วไม่มีใครต้อง "เก็บรายชื่อเดิม": GC จะดำเนินการตามที่ต้องการ
user2864740

8
@ user2864740: ใช่นั่นเป็นความจริงถ้าแหล่งที่มาเป็นรายการในหน่วยความจำอย่างเคร่งครัด หากอ่านจากตัวอย่างไฟล์คุณจะต้องเปิดไฟล์ไว้จนกว่าคุณจะประมวลผลผลลัพธ์จากไฟล์Select.
Guffa

19

คำตอบแรกไม่ควรเป็นคำตอบที่ยอมรับ ฉันเป็นอดีต MVP C # Microsoft ปี 2007

ในทางตรงกันข้ามกับการตอบสนองที่ได้รับการยอมรับ, ConvertAllมีประสิทธิภาพมากขึ้นกว่าการรวมกันของและSelectToList()

ก่อนอื่นConvertAllคือเร็วกว่าอย่างเคร่งครัดและใช้หน่วยความจำขั้นต่ำในการทำเช่นนั้น เหมือนกับ Array.ConvertAll vs Select และ ToArray สิ่งนี้จะชัดเจนมากขึ้นด้วยอาร์เรย์ที่มีความยาวมากขึ้นหรือการเรียกหลายสายภายในลูป

1) ConvertAllทราบขนาดของรายการสุดท้ายและหลีกเลี่ยงการจัดสรรอาร์เรย์ฐานใหม่ ToList() จะทำการปรับขนาดอาร์เรย์หลาย ๆ ครั้ง

2) ToListจะทำการIEnumerable<>โทรอินเทอร์เฟซที่ช้าลงในขณะที่ConvertAllจะวนผ่านอาร์เรย์พื้นฐานโดยไม่ต้องมีการโทรเพิ่มเติมหรือการตรวจสอบช่วง

3) เลือกจะสร้างIEnumerable<T>วัตถุพิเศษ


1

ฉันรู้ว่ามันช้าไปหน่อย แต่ฉันยังได้เพิ่มเพราะอาจมีประโยชน์สำหรับคนอื่น ๆ ในอนาคต

เมื่อใช้ในนิพจน์แบบสอบถาม EntityFramework ไม่แนะนำให้ใช้ ConvertAll () เนื่องจากจะประเมินนิพจน์แทนที่จะปล่อยให้เป็นนิพจน์เพื่อใช้ในอนาคต สิ่งนี้ทำให้ประสิทธิภาพการดำเนินการสืบค้นฐานข้อมูลลดลงอย่างมากเนื่องจากจะต้องทำการเรียกจำนวนครั้งก่อนที่จะประเมินนิพจน์สุดท้าย


9
ไม่มาก เป็นจุด Guffa ออกในคำตอบนี้ , เป็นวิธีการในการConvertAll List<T>เมื่อคุณมีรายการคุณได้ประเมินนิพจน์ของคุณแล้ว แต่คุณพูดถูก - ถ้าคุณไม่ต้องการประเมินทั้งหมดSelectจะดีกว่า
Wai Ha Lee
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.