2009-07-29 27 views
101

Trong ASP.NET C# Tôi có một cấu trúc:Chọn Nhiều Fields từ Danh sách trong LINQ

public struct Data 
{ 
    public int item1; 
    public int item2; 
    public int category_id; 
    public string category_name; 
} 

và tôi có một danh sách những người. Tôi muốn chọn category_idcategory_name, chạy một số DISTINCT và cuối cùng là ORDERBY trên category_name.

Dưới đây là những gì tôi có bây giờ:

List<Data> listObject = getData(); 
string[] catNames = listObject 
        .Select(i=> i.category_name) 
        .Distinct() 
        .OrderByDescending(s => s) 
        .ToArray(); 

Điều này rõ ràng chỉ lấy tên thể loại. Câu hỏi của tôi là, làm cách nào để có nhiều trường và cấu trúc dữ liệu nào tôi sẽ lưu trữ trong (không phải là string[])?

EDIT

Sử dụng danh sách các cấu trúc không được đặt trong đá. Nếu nó sẽ được khuyến khích để thay đổi cấu trúc dữ liệu sao lưu của tôi để làm cho lựa chọn dễ dàng hơn (tôi sẽ viết rất nhiều trong số này) sau đó tôi sẵn sàng đề nghị.

+8

Trong khi đó là không liên quan đến phía LINQ, tôi sẽ * mạnh mẽ * khuyên bạn không nên sử dụng các cấu trúc có thể thay đổi hoặc các trường công cộng. Cá nhân tôi hiếm khi tạo ra cấu trúc ở nơi đầu tiên, nhưng các cấu trúc có thể thay đổi chỉ yêu cầu sự cố. –

+0

@Jon Skeet Cảm ơn. Tôi sẽ chuyển nó thành một lớp thông thường với các thành viên riêng. – Chet

+1

@Jon Skeet Tại sao? – Midhat

Trả lời

175

loại Anonymous cho phép bạn chọn các lĩnh vực tùy vào cấu trúc dữ liệu được gõ mạnh sau này trong mã của bạn:

var cats = listObject 
    .Select(i => new { i.category_id, i.category_name }) 
    .Distinct() 
    .OrderByDescending(i => i.category_name) 
    .ToArray(); 

Vì bạn (dường như) cần lưu trữ nó r sử dụng sau này, bạn có thể sử dụng toán tử groupby:

Data[] cats = listObject 
    .GroupBy(i => new { i.category_id, i.category_name }) 
    .OrderByDescending(g => g.Key.category_name) 
    .Select(g => g.First()) 
    .ToArray(); 
+0

Tôi muốn sử dụng riêng biệt trên 1 cột và lấy nhiều cột.SO làm thế nào tôi có thể làm điều đó? –

+1

Tôi chưa từng nghĩ 'Chọn' thành loại mới. Trong trường hợp của tôi, tôi đã chọn vào một 'KeyValuePair' mới. – cjbarth

20

Bạn có thể sử dụng một loại vô danh:

.Select(i => new { i.name, i.category_name }) 

Trình biên dịch sẽ tạo ra mã cho một lớp học với namecategory_name tính và trả về thể hiện của lớp đó. Bạn cũng có thể chỉ định tên thuộc tính theo cách thủ công:

i => new { Id = i.category_id, Name = i.category_name } 

Bạn có thể có số lượng thuộc tính tùy ý.

3
var result = listObject.Select(i => new{ i.category_name, i.category_id }) 

Điều này sử dụng các loại ẩn danh, do đó bạn phải có từ khóa var, vì loại biểu thức kết quả không được biết trước.

5

Đây là nhiệm vụ mà anonymous types rất phù hợp. Bạn có thể trả về các đối tượng của một kiểu được trình biên dịch tạo tự động, suy ra từ cách sử dụng.

Cú pháp là của mẫu này:

new { Property1 = value1, Property2 = value2, ... } 

Đối với trường hợp của bạn, hãy thử một cái gì đó như sau:

var listObject = getData(); 
var catNames = listObject.Select(i => 
    new { CatName = i.category_name, Item1 = i.item1, Item2 = i.item2 }) 
    .Distinct().OrderByDescending(s => s).ToArray(); 
22
var selectedCategories = 
    from value in 
     (from data in listObject 
     orderby data.category_name descending 
     select new { ID = data.category_id, Name = data.category_name }) 
    group value by value.Name into g 
    select g.First(); 

foreach (var category in selectedCategories) Console.WriteLine(category); 

Sửa: Made nó nhiều LINQ-ey!

+0

Haha, cảm ơn, vâng, tôi đánh giá cao sự trợ giúp. Rõ ràng đây không phải là câu hỏi khó nhất trên thế giới. – Chet

+0

@IRBMe Xin lỗi, câu hỏi nhỏ. 'Giá trị' chính xác là gì? –

3
(from i in list 
select new { i.category_id, i.category_name }) 
.Distinct() 
.OrderBy(i => i.category_name); 
2

Bạn có thể chọn nhiều trường bằng LINQ Chọn như được hiển thị ở trên trong các ví dụ khác nhau, điều này sẽ trở lại dưới dạng Kiểu ẩn danh. Nếu bạn muốn tránh loại ẩn danh này thì đây là mẹo đơn giản.

var items = listObject.Select(f => new List<int>() { f.Item1, f.Item2 }).SelectMany(item => item).Distinct(); 

Tôi nghĩ rằng điều này giải quyết vấn đề của bạn

2

Bạn có thể làm cho nó một KeyValuePair, vì vậy nó sẽ trả về một "IEnumerable<KeyValuePair<string, string>>"

Vì vậy, nó sẽ là như thế này:

.Select(i => new KeyValuePair<string, string>(i.category_id, i.category_name)).Distinct(); 
Các vấn đề liên quan