2009-06-09 42 views
19

phép nói rằng tôi có cụt Person lớp này:C#: Làm thế nào để sử dụng phương pháp Enumerable.Aggregate

class Person 
{ 
    public int Age { get; set; } 
    public string Country { get; set; } 

    public int SOReputation { get; set; } 
    public TimeSpan TimeSpentOnSO { get; set; } 

    ... 
} 

tôi có thể sau đó nhóm trên AgeCountry như thế này:

var groups = aListOfPeople.GroupBy(x => new { x.Country, x.Age }); 

Sau đó, tôi có thể xuất tất cả các nhóm có tổng số danh tiếng như sau:

foreach(var g in groups) 
    Console.WriteLine("{0}, {1}:{2}", 
     g.Key.Country, 
     g.Key.Age, 
     g.Sum(x => x.SOReputation)); 

Câu hỏi của tôi là, làm thế nào tôi có thể nhận được một khoản tiền của tài sản TimeSpentOnSO? Phương pháp Sum sẽ không hoạt động trong trường hợp này vì nó chỉ dành cho int và như vậy. Tôi nghĩ rằng tôi có thể sử dụng phương pháp Aggregate, nhưng nghiêm túc không thể tìm ra cách sử dụng nó ... Tôi đang cố gắng tất cả các loại tài sản và các loại trong các kết hợp khác nhau nhưng trình biên dịch sẽ không nhận ra nó.

foreach(var g in groups) 
    Console.WriteLine("{0}, {1}:{2}", 
     g.Key.Country, 
     g.Key.Age, 
     g.Aggregate( what goes here?? )); 

Tôi hoàn toàn có hiểu sai phương pháp tổng hợp không? Hay chuyện gì đang xảy ra? Có một số phương pháp khác tôi nên sử dụng thay thế? Hoặc tôi có phải viết biến thể Sum của riêng mình cho TimeSpan s không?

Và để thêm vào mớ hỗn độn, điều gì xảy ra nếu Người là một lớp ẩn danh, kết quả từ ví dụ: Select hoặc tuyên bố GroupJoin?


Chỉ cần tìm ra rằng tôi có thể làm cho công việc Aggregate phương pháp nếu tôi đã làm một Select trên TimeSpan sở hữu đầu tiên ... nhưng tôi thấy rằng loại gây phiền nhiễu ... Vẫn không cảm thấy tôi hiểu phương pháp này ở tất cả ...

foreach(var g in groups) 
    Console.WriteLine("{0}, {1}:{2}", 
     g.Key.Country, 
     g.Key.Age, 
     g.Select(x => x.TimeSpentOnSO) 
     g.Aggregate((sum, x) => sum + y)); 
+0

Tôi chỉ muốn chỉ ra rằng Tổng hợp (giảm) là một trong những điều thú vị nhất trên thế giới hiện nay mà tôi đã gặp phải tình huống mà tôi muốn sử dụng nó. :) –

Trả lời

2

Một sự kết hợp của Chris và Daniels câu trả lời giải quyết nó cho tôi. Tôi cần phải khởi tạo TimeSpan, và tôi đã làm mọi thứ theo thứ tự sai. Giải pháp là:

foreach(var g in groups) 
    Console.WriteLine("{0}, {1}:{2}", 
     g.Key.Country, 
     g.Key.Age, 
     g.Aggregate(TimeSpan.Zero, (sum, x) => sum + x.TimeSpentOnSO)); 

Cảm ơn!

Và cũng ... D'oh!

1

Bạn có thể viết TimeSpanSum phương pháp ...

public static TimeSpan Sum(this IEnumerable<TimeSpan> times) 
{ 
    return TimeSpan.FromTicks(times.Sum(t => t.Ticks)); 
} 
public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source, 
    Func<TSource, TimeSpan> selector) 
{ 
    return TimeSpan.FromTicks(source.Sum(t => selector(t).Ticks)); 
} 

Ngoài ra, MiscUtil có các phương thức Sum được bật chung, vì vậy Sum chỉ hoạt động trên TimeSpan tốt (vì có một toán tử được xác định là TimeSpan+TimeSpan=>TimeSpan).

Chỉ xin không cho tôi biết số ... nó sẽ làm tôi sợ ...

+0

Vâng, đó là loại đường dẫn sao lưu của tôi. Nhưng tôi vẫn muốn tìm hiểu làm thế nào mà phương pháp tổng hợp thực sự hoạt động. Bởi vì nó làm phiền tôi rằng tôi dường như không thể sử dụng nó thành công: p – Svish

+0

Và vâng, hãy giữ con số đó mãi mãi bí mật. Không bao giờ nghĩ đến việc đăng bất kỳ loại số liệu thống kê nào giống như vậy ở đây trên SO: p (Mặc dù tôi phải nói loại tò mò muốn ... nhưng giữ riêng tư trong trường hợp đó!) – Svish

23
List<TimeSpan> list = new List<TimeSpan> 
    { 
     new TimeSpan(1), 
     new TimeSpan(2), 
     new TimeSpan(3) 
    }; 

TimeSpan total = list.Aggregate(TimeSpan.Zero, (sum, value) => sum.Add(value)); 

Debug.Assert(total.Ticks == 6); 
+0

Khởi tạo với TimeSpan.Zero. Rất tốt. Tuy nhiên, đây là một danh sách TimeSpans, tôi cần một danh sách thứ gì đó khác với thuộc tính TimeSpan. Nhưng tôi đã tìm ra. Cảm ơn! – Svish

14
g.Aggregate(TimeSpan.Zero, (i, p) => i + p.TimeSpentOnSO) 

Về cơ bản, các đối số đầu tiên để tổng hợp là một initializer, được sử dụng như giá trị đầu tiên của "i" trong hàm được truyền trong đối số thứ hai. Nó sẽ lặp qua danh sách, và mỗi lần, "i" sẽ chứa tổng số cho đến nay.

Ví dụ:

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

nums.Aggregate(0, (x,y) => x + y); // sums up the numbers, starting with 0 => 15 
nums.Aggregate(0, (x,y) => x * y); // multiplies the numbers, starting with 0 => 0, because anything multiplied by 0 is 0 
nums.Aggregate(1, (x,y) => x * y); // multiplies the numbers, starting with 1 => 120 
+0

Điều này là với ints, mà tôi đã có loại giải quyết. Nhưng cảm ơn vì đã dọn dẹp cách khởi tạo nó! – Svish

+0

Xin lỗi, ban đầu nó đang sử dụng int. Tôi đã đọc sai câu hỏi, nhưng điều này sẽ phù hợp với bạn, cũng như giải thích cách tổng hợp hoạt động nói chung. –

0

Bạn có thể tóm tắt trên một trong những Tổng số thuộc tính của đối tượng TimeSpan. Ví dụ, bạn có thể nhận được các TotalHours đại diện của thời gian dành cho SO như thế này:

g.Sum(x => x.SOReputation.TotalHours) 

Tôi tin rằng điều này sẽ cung cấp cho bạn những kết quả mà bạn đang tìm kiếm, nhưng với sự báo trước rằng bạn sẽ phải đặt đơn vị đo theo những gì bạn cần (giờ, phút, giây, ngày, v.v.)

+0

Thực ra đây là những gì tôi đã làm, nhưng vì những lý do khác. Vẫn hạnh phúc vì cuối cùng tôi đã hiểu được phương pháp Tổng hợp (Mặc dù không phải là một chuyên gia: p). – Svish

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