2017-07-07 20 views
5

Tôi đã từng sử dụng phương pháp Stream#Peek của Java rất nhiều vì đây là phương pháp hữu ích để gỡ lỗi hoạt động của luồng trung gian. Đối với những người bạn của những người không quen thuộc với các phương pháp Stream#Peek, dưới đây cho thấy các định nghĩa của nó:Tương đương với phương pháp Stream # Peek của Java trong Linq C# là gì?

Stream<T> peek(Consumer<? super T> action)

Trả về một dòng gồm các yếu tố của dòng này, bổ sung thực hiện hành động cung cấp trên mỗi phần tử là các yếu tố được tiêu thụ từ luồng kết quả. Đây là hoạt động trung gian .

Hãy xem xét ví dụ này đơn giản dưới đây:

List<Integer> integerList = Arrays.asList(1,2,3,4,5,6,7,8,9,10); 
List<Integer> result = integerList.stream() 
            .filter(i -> i % 2 == 0) 
            .peek(System.out::println) 
            .collect(Collectors.toList()); 

Với phương pháp Stream#Peek, điều này về cơ bản nên cho phép tôi để in tất cả các số chẵn để giao diện điều khiển để tôi có thể kiểm tra để xem nếu đó là những gì Tôi mong chờ.

Tôi đã cố gắng để tìm một câu trả lời cho câu hỏi trong tầm tay nhưng dường như không thể tìm thấy một phương pháp tương tự trong C#, không ai biết tương đương với Java Stream#Peek hoặc một số phương pháp khác với hành vi tương tự?

+0

Có phương pháp ForEach trong lớp List (có một số tranh luận về lý do không có sẵn cho IEnumerable), vì vậy bạn cần gọi "ToList" trước khi sử dụng. Mặc dù nó trả về void, không phải một danh sách khác. Nhưng nó là tầm thường để viết phương pháp mở rộng của riêng bạn cho IEnumerable mà làm điều đó. – user1242967

+0

@ user1242967 Không có * tranh luận * về lý do tại sao nó không tồn tại cho 'IEnumerable'. Có cuộc tranh luận về việc liệu nó có phải là một ý tưởng hay cho 'IEnumerable' hay không, nhưng tại sao nó không được đặt ra rõ ràng và không có vấn đề gì. – Servy

+0

@Servy Vâng, từ ngữ xấu về phía tôi. – user1242967

Trả lời

5

Không có tương đương với Peek trong LINQ - ví dụ: không có phương pháp mà thực hiện một số yếu tố hành động nguồn lợi nhuận. Có một phương thức ForEach trong lớp List thực hiện một phép toán trên mỗi phần tử, nhưng nó không trả về các phần tử nguồn và như đã nói, nó không phải là một phần mở rộng IEnumerable.

Nhưng bạn có thể dễ dàng viết phần mở rộng của riêng bạn

public static IEnumerable<T> Peek<T>(this IEnumerable<T> source, Action<T> action) 
{ 
    if (source == null) throw new ArgumentNullException(nameof(source)); 
    if (action == null) throw new ArgumentNullException(nameof(action)); 

    return Iterator(); 

    IEnumerable<T> Iterator() // C# 7 Local Function 
    { 
     foreach(var item in source) 
     { 
      action(item); 
      yield return item; 
     } 
    } 
} 
+1

Tôi nghĩ rằng việc khai báo một hàm cục bộ chỉ để thực hiện nó và trả về kết quả là dư thừa. Bạn sẽ nhận được hiệu ứng tương tự với ít mã hơn chỉ với khối foreach. –

+1

@MattJohnson và cách kiểm tra thông số sẽ hoạt động với thực thi hoãn lại? –

+0

Thực hiện trì hoãn được thực hiện thông qua việc sử dụng 'lợi nhuận' - không phải bằng cách gọi hàm. Bạn vẫn nhận được thực thi trì hoãn cả hai như hiện đang viết, và nếu bạn inline chức năng. (Lưu ý rằng bạn không trả lại hàm nào cả, bạn chỉ đang thực hiện nó.) –

1

EDIT: câu trả lời này đã lỗi thời, sau khi chỉnh sửa cho câu hỏi gốc. Câu hỏi đầu tiên được diễn đạt với ý định peek -ing tất cả các giá trị filter -ed, sau đó thực hiện findFirst:

List<Integer> integerList = Arrays.asList(1,2,3,4,5,6,7,8,9,10); 
Optional<Integer> result = integerList.stream() 
             .filter(i -> i % 2 ==0== 0) 
             .peek(System.out::println) 
             .findFirst(); 

Theo như tôi biết, không có giải pháp tích hợp LINQ để làm điều này, vì vậy đây là một phương pháp khuyến nông:

public static IEnumerable<T> Peek<T>(this IEnumerable<T> source, Action<T> action) 
{ 
    using (var iterator = source.GetEnumerator()) 
    { 
     while (iterator.MoveNext()) 
     { 
      action(iterator.Current); 
     } 
    } 

    using (var iterator = source.GetEnumerator()) 
    { 
     while (iterator.MoveNext()) 
     { 
      yield return iterator.Current; 
     } 
    } 
} 

cách sử dụng:

var integerList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
int? result = integerList.Where(i => i % 2 == 0) 
         .Peek(i => Console.WriteLine(i)) 
         .FirstOrDefault(); 

Console.WriteLine(result); 

Output:

2 
4 
6 
8 
10 
2 
4

Bạn có thể sử dụng một Select với một Statement Lambda cho việc này.Hãy xem xét:

var integerList = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
var result = integerList 
    .Where(i => i % 2 == 0) 

    // this select uses a statement lambda 
    .Select(i => 
    { 
     Console.WriteLine(i); 
     return i; 
    }) 

    .Whatever(...); 
Các vấn đề liên quan