2009-07-16 33 views
8

Tôi có một lớp:Sử dụng LINQ to Get Sum/trung bình của một danh sách với các đối tượng tùy chỉnh

public class PointD 
{ 
    public double X 
    { get; set; } 
    public double Y 
    { get; set; } 

    public PointD(double x, double y) 
    { 
     X = x; 
     Y=y; 
    } 
    //operator for +,-, * and/are overridden 
} 

Cho một list<PointD>, làm thế nào để có được tỷ lệ trung bình của nó sử dụng LINQ? Một for vòng lặp tương đương sẽ là một cái gì đó như thế này:

double xx, yy; 
    for (int i=0; i< ptlist.Count; i++) 
    { 
     xx+=ptlist[i].X; 
     yy+=ptlist[i].Y; 
    } 
    return new PointD(){X=xx, Y=yy}; 

Bạn có thể sử dụng bất kỳ chỉ built-in chức năng LINQ. Bạn không thể xác định tiện ích mở rộng sẽ xử lý chức năng này.

Bất kỳ ý tưởng nào?

Chỉnh sửa: Tất nhiên, bạn có thể sử dụng hai phương thức mở rộng riêng biệt Sum để tính tổng hợp cho thành phần X và Y trước khi hợp nhất chúng. Nhưng đây không phải là điều tôi muốn. Điều tôi muốn là một truy vấn/phương pháp thực hiện công việc

+0

sẽ không có hai khoản tiền hoạt động? Một cái gì đó như ptlist.Sum (p => p.X); và ptlist.Sum (p => p.Y); – albertjan

+0

"làm thế nào để có được mức trung bình của nó bằng cách sử dụng LINQ?" .. Tôi nghĩ rằng bạn có nghĩa là số tiền – James

+0

@ the_ajp: nó có thể làm việc, nhưng tôi muốn đặt tất cả mọi thứ trong một truy vấn, đó chỉ là nó. – Graviton

Trả lời

13

chức năng Aggregate sẽ có ích ở đây.

var sum = list.Aggregate((acc, cur) => acc + cur); 
var average = list.Aggregate((acc, cur) => acc + cur)/list.Count; 

Chỉ cần đảm bảo rằng bạn có / điều hành được định nghĩa với nhiều loại PointDint, và điều này sẽ thực hiện công việc.

Lưu ý: Tôi không hoàn toàn chắc chắn liệu bạn muốn tổng hoặc trung bình ở đây (câu hỏi của bạn có phần mơ hồ về điều này), nhưng tôi đã bao gồm các ví dụ cho cả hai.

+0

PointD là một kiểu tham chiếu, do đó, tùy thuộc vào cách các toán tử được triển khai, bạn có thể nhận được một ArgumentNullException hoặc NullReferenceException tại đây. Có thể có giá trị cung cấp một hạt giống không null cho người tích lũy. –

+0

Đây là một trong những tốt, nhưng tôi không hoàn toàn hiểu tại sao tôi không thể nghĩ về nó .. duh !! – Graviton

+0

@Greg Beech: Đó là một điểm công bằng. Tôi tự động giả định nó là một 'struct' (như là' Point' type trong WPF/System.Drawing), nhưng có vẻ như anh ta đã định nghĩa nó như là một lớp. @Ngu Soon Hui: Tôi khuyên bạn nên xác định loại 'PointD' của bạn dưới dạng' struct', trừ khi bạn có lý do chính đáng khác. 'Tổng hợp' sau đó sẽ sử dụng' mặc định (PointD) 'làm hạt giống, có nghĩa là mọi thứ sẽ hoạt động tốt. – Noldorin

6

Bạn cần sử dụng phương pháp Aggregate để bạn có thể cung cấp chức năng tổng hợp của riêng mình (Sum). Một cái gì đó như:

points.Aggregate(new PointD(0, 0), (a, p) => a + p); 

Tôi biết bạn nói rằng bạn không muốn bất kỳ phương pháp bổ sung được xác định, nhưng nếu điều này là một hoạt động chung tôi muốn được xu hướng viết một phương pháp khuyến nông cho điều này, tức là

public static PointD Sum(this IEnumerable<PointD> source) 
{ 
    return source.Aggregate(new PointD(0, 0), (a, p) => a + p); 
} 

Bởi vì nó có thể đọc được nhiều hơn nữa để có thể viết:

points.Sum(); 
+1

Nếu anh ta đã quá tải các toán tử cho 'PointD', không cần phải xác định lại bổ sung. – Noldorin

+0

Ồ vâng. Không thấy điều đó trong câu hỏi. OK, tôi sẽ chỉnh sửa. –

+0

Bạn có thể giải thích mục đích của 'mới PointD (0, 0), '? – jxramos

0
[Fact] 
    public void CanAddManyPointDs() 
    { 
     var points = new[]{ 
      new PointD(1,1), 
      new PointD(2,3), 
      new PointD(3,4), 
     }; 

     var result = points.Aggregate((p1, p2) => new PointD(p1.X + p2.X, p1.Y + p2.Y)); 
     Assert.Equal(result.X,6); 
     Assert.Equal(result.Y,8); 
    } 
Các vấn đề liên quan