2010-03-22 38 views
8

Tôi có 3 (Chỉnh sửa) loại trừ lẫn nhau IEnumerables mà tôi muốn lặp lại. Tôi muốn làm một cái gì đó như thế này:Foreach qua bộ sưu tập của IEnumerables

IEnumerable<Car> redCars = GetRedCars(); 
IEnumerable<Car> greenCars = GetGreenCars(); 
IEnumerable<Car> blueCars = GetBlueCars(); 

foreach(Car c in (redCars + greenCars + blueCars)) { 
    c.DoSomething(); 
} 

... 

Cách tốt nhất tôi có thể nghĩ đến là:

... 
List<Car> allCars = new List(); 
allCars.AddRange(redCars); 
allCars.AddRange(greenCars); 
allCars.AddRange(blueCars); 
foreach(car in allCars) { 
    ... 
} 
... 

Có cách nào ngắn gọn hơn để làm điều này? Có vẻ như việc kết hợp IEnumberables sẽ không đáng kể.

Trả lời

20

Với LINQ:

foreach(car in redCars.Concat(greenCars).Concat(blueCars)) { 
    //... 
} 

Đối với thông tin, sự khác biệt ở đây giữa UnionConcatUnion sẽ làm việc thêm để đảm bảo tính độc đáo; vì vậy nếu bạn không mong đợi các bản sao (hoặc cách khác: đừng bận tâm đến chúng) thì Concat sẽ nhanh hơn.

+2

Heh ... Tôi bắt đầu với Concat và sau đó đã đi đến Liên minh và sau đó quyết định tôi không thể quyết định nên sử dụng, vì vậy tôi đã xóa câu trả lời của tôi. Tôi thích bạn giải thích sự khác biệt tốt hơn anyway. +1 – Randolpho

+0

Chính xác những gì tôi đang tìm kiếm. Cảm ơn! – sdr

+0

@sdr: Lưu ý rằng có sự cân bằng thời gian/không gian tại đây. Giả sử bạn không có ba nhưng hai mươi danh sách như vậy với mười nghìn yếu tố. Phương pháp của bạn (ghép tất cả chúng lại với nhau thành một danh sách lớn) chiếm khoảng 20 x 10K tham chiếu bổ sung và có các hoạt động sao chép tham chiếu 20 x 10K. Làm 20 concve ngây thơ, mặt khác, chiếm không tham khảo thêm, nhưng concested lồng nhau có một gánh nặng sao chép dựa trên chiều sâu của chúng làm tổ, do đó sẽ có 10 x 11 x 10K = 110K bản sao, không phải 20K bản sao. Xem http://blogs.msdn.com/wesdyer/archive/2007/03/23/all-about-iterators.aspx để biết chi tiết. –

0

Sử dụng phương pháp LINQ Union.

foreach(Car c in redCars.Union(greenCars).Union(blueCars)) 
{ 
    c.DoSomething(); 
} 
+0

Nếu bạn hoàn toàn cần thực hiện điều này trong một vòng lặp, tôi sẽ sử dụng LINQ. –

+0

Không nghĩ về điều đó. Nhưng điều này không phải là quá nhiều vì nó phải so sánh tất cả? Đặc biệt là vì ba nhóm là loại trừ lẫn nhau. – sdr

+1

Để biết thông tin, 'Union' sẽ đắt hơn' Concat' ở đây và có thể tạo ra một kết quả khác với phương thức 'AddRange' (về cơ bản là' Concat'). –

0

Có lý do nào bạn cần làm trong một vòng lặp không? Nếu vậy, cách thứ hai có lẽ là tốt nhất. Không có gì sẽ hoạt động như cách đầu tiên.

Trừ khi có nhu cầu quan trọng để làm điều đó trong một vòng lặp, tôi sẽ làm điều đó trong ba vòng sẽ có nhiều thời gian hiệu quả hơn.

+1

Tôi nghĩ rằng "hiệu quả hơn về thời gian" là một tuyên bố lớn. Cũng lưu ý rằng việc tạo danh sách (với phân bổ, sao chép, v.v ...) cũng có phí trên. Và có rất nhiều * là * cái gì đó sẽ hoạt động như cách đầu tiên. –

+0

@Scott, nếu anh ta làm việc với mỗi chiếc xe theo cùng một cách, tại sao anh ta muốn nhiều hơn một vòng? Đó chỉ là mã dự phòng. –

3

Như đã lưu ý trong các câu trả lời khác, Union thực hiện thêm công việc để loại bỏ các bản sao, Concat chỉ đơn giản là ghép nối các chuỗi. Tuy nhiên, như tôi đã lưu ý trong một bình luận ở trên, có những chi phí hiệu suất cho các concats lồng nhau sâu sắc. Bạn có thể xem xét cũng sử dụng một SelectMany để san bằng một loạt các vòng lặp:

var carLists = new[]{GetRedCars(), GetGreenCars(), GetBlueCars()}; 
var allCars = from carList in carLists 
       from car in carList 
       select car; 
foreach(var c in allCars) { ... } 

Bạn có thể thấy rằng để được linh hoạt hơn, bạn nên khám phá ra rằng bạn thực sự có cách hơn ba danh sách này để lặp.

Các vấn đề liên quan