2009-03-24 38 views
5

Tại sao tôi không thể làm điều gì đó như thế này?Sử dụng câu lệnh lambda có điều kiện với hành động foreach trên danh sách

Nếu tôi có một List<String> myList dân cư với các mặt hàng, tôi muốn để có thể hoạt động trên mỗi thành viên một cách có điều kiện như vậy:

myList.ForEach(a => { if (a.Trim().Length == 0) a = "0.0"; }) 

Nhưng điều này sẽ không biên dịch. Tôi đoán nó có liên quan đến việc thiếu giá trị trả về?

Tôi đang cố gắng chuẩn bị danh sách các chuỗi để chuyển đổi thành gấp đôi và tôi muốn các mục trống hiển thị '0.0' để tôi chỉ có thể chuyển đổi toàn bộ danh sách trong một lần.

+1

tôi khuyên bạn đến thăm www.lambdaexpression.net – Delashmate

Trả lời

6

ForEach không thể thay đổi được, nó không thay đổi cấu trúc dữ liệu theo bất kỳ cách nào.

Bạn có thể:

  1. Xử lý vòng lặp chính mình, với một chỉ số
  2. Sản xuất một danh sách mới, sử dụng .Chọn và ToList (miễn là bạn đang sử dụng .NET 3.5)

Ví dụ về # 1:

for (Int32 index = 0; index < myList.Count; index++) 
    if (myList[index].Trim().Length == 0) 
     myList[index] = "0.0"; 

Với .NET 3.5 và LINQ:

myList = (from a in myList 
      select (a.Trim().Length == 0) ? "0.0" : a).ToList(); 

Với .NET 3.5, không sử dụng LINQ-cú pháp, nhưng sử dụng LINQ-code:

myList = myList.Select(a => (a.Trim().Length == 0) ? "0.0" : a).ToList(); 

Sửa: Nếu bạn muốn tạo ra một danh sách mới của đôi, bạn cũng có thể làm điều đó trong một lần sử dụng LINQ:

List<Double> myDoubleList = 
    (from a in myList 
    select (a.Trim().Length == 0 ? "0" : a) into d 
    select Double.Parse(d)).ToList(); 

Lưu ý rằng việc sử dụng "0.0" thay vì chỉ "0" dựa vào dấu thập phân là điểm dừng đầy đủ c haracter. Trên hệ thống của tôi không phải vậy, vì vậy tôi đã thay thế nó bằng "0", nhưng cách thích hợp hơn là thay đổi cuộc gọi thành Double.Parse để có định dạng số rõ ràng, như sau:

List<Double> myDoubleList = 
    (from a in myList 
    select (a.Trim().Length == 0 ? "0.0" : a) into d 
    select Double.Parse(d, CultureInfo.InvariantCulture)).ToList(); 
+0

Hmmm ok, là có bất kỳ phương pháp mở rộng sẽ cho phép bạn để hoạt động trên mỗi mục trong danh sách? – Alex

+0

Không phải là tôi biết, và tôi nghi ngờ nó, hầu hết các phương pháp Linq được xây dựng trong một phong cách chức năng, mà không cho phép thay đổi đầu vào trong bất kỳ cách nào. –

+0

Cảm ơn lời giải thích tuyệt vời. – Alex

4

những gì bạn có thể muốn là:

public static void MutateEach(this IList<T> list, Func<T, T> mutator) 
{ 
    int count = list.Count; 
    for (int n = 0; n < count; n++) 
     list[n] = mutator(list[n]); 
} 

nào sẽ cho phép:

myList.MutateEach(a => (a.Trim().Length == 0) ? "0.0" : a); 

Chỉ cần đặt các phương pháp MutateEach trong một lớp public static của riêng bạn và chắc chắn rằng bạn có một sử dụng chỉ thị rằng sẽ tìm thấy nó.

Cho dù đó là giá trị xác định một cái gì đó như thế này phụ thuộc vào mức độ thường xuyên bạn sẽ sử dụng nó. Lưu ý rằng nó phải là một phần mở rộng trên IList thay vì IEnumerable, vì vậy chúng tôi có thể thực hiện các cập nhật, điều này làm cho bản cập nhật ít phổ biến hơn.

+0

+1 để đặt tên, điều này sẽ làm cho tiện ích này trở thành tiện ích mở rộng tốt. –

+1

Các bạn thật tuyệt vời. Tôi học điều gì đó mỗi khi tôi đặt câu hỏi trên trang web này. – Alex

0

@ daniel-earwicker MutateEach Giải pháp mở rộng là giải pháp tốt.


Mặc dù, trả lại một mới List, bạn có tùy chọn để sử dụng List.ConvertAll<TTo>(Converter<TFrom,TTo>(Func<TFrom, TTo>)), mà đã được khoảng từ NET 2.0.

Nó không phải là Linq hoặc Lambda.

List<String> nodeStringList = new List<String>(new String[] { "", "0.5 ", " 1.1"}); 

nodeStringList = nodeStringList.ConvertAll<String>((c) => (c.Value.Trim().Length != 0) ? c.Value.Trim() : "0.0"); 

MSDN Reference - List.ConvertAll

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