Chọn nhiều lĩnh vực từ danh sách trong Linq


128

Trong ASP.NET C # tôi có một cấu trúc:

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 cái đó Tôi muốn chọn category_idcategory_namechạy một DISTINCTvà cuối cùng một ORDERBYngày category_name.

Đâ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ỉ nhận được tên danh mục. Câu hỏi của tôi là, làm thế nào để tôi có được nhiều trường và tôi sẽ lưu trữ cấu trúc dữ liệu này trong (không phải a string[])?

BIÊN TẬP

Sử dụng một danh sách các cấu trúc không được đặt trong đá. Nếu có thể thay đổi cấu trúc dữ liệu sao lưu của tôi để giúp lựa chọn dễ dàng hơn (tôi sẽ viết rất nhiều trong số này) thì tôi sẵn sàng nhận đề xuất.


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

@Jon Skeet Cảm ơn. Tôi sẽ chuyển đổi nó thành một lớp học bình thường với các thành viên tư nhân.
Chet

1
@ REhat: Các cấu trúc có thể gây đột biến gây ra tất cả các loại vấn đề, vì chúng không hành xử như mọi người mong đợi. Và các lĩnh vực công cộng cung cấp hoàn toàn thiếu đóng gói.
Jon Skeet

@Jon Skeet. Bạn có thể cụ thể hơn với những cạm bẫy của các cấu trúc đột biến, hoặc chỉ cho tôi đọc.
Giữa

2
@Unhat: Hãy xem stackoverflow.com/questions/441309/why-are-mutable-structs-evil cho điểm bắt đầu.
Jon Skeet

Câu trả lời:


228

Các loại ẩn danh cho phép bạn chọn các trường tùy ý vào các 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ó để sử dụng sau, 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();

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

1
Tôi chưa bao giờ nghĩ đến Selectmột loại mới. Trong trường hợp của tôi, tôi đã chọn một cái mới KeyValuePair.
cjbarth

26
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);

Chỉnh sửa : Làm cho nó nhiều hơn LINQ-eye!


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

@IRBMe Xin lỗi, câu hỏi nhỏ. Chính xác 'giá trị' là gì?
Fernando S. Kroes

23

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

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

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

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

Bạn có thể có số lượng tài sản tùy ý.


6

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 Loại ẩ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


5

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

Cú pháp có dạng 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();

4
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 từ khóa var, vì loại kết quả của biểu thức không được biết trước.


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

3

Bạn có thể biến nó thành KeyValuePair, vì vậy nó sẽ trả về "IEnumerable<KeyValuePair<string, string>>"

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

.Select(i => new KeyValuePair<string, string>(i.category_id, i.category_name )).Distinct();

Điều này thêm sự phức tạp không cần thiết mà không có lợi ích
Matze

2
public class Student
{
    public string Name { set; get; }
    public int ID { set; get; }
}

class Program
{
  static void Main(string[] args)
    {
        Student[] students =
        {
        new Student { Name="zoyeb" , ID=1},
        new Student { Name="Siddiq" , ID=2},
        new Student { Name="sam" , ID=3},
        new Student { Name="james" , ID=4},
        new Student { Name="sonia" , ID=5}
        };

        var studentCollection = from s in students select new { s.ID , s.Name};

        foreach (var student in studentCollection)
        {
            Console.WriteLine(student.Name);
            Console.WriteLine(student.ID);
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.