Khác biệt trong Linq chỉ dựa trên một lĩnh vực của bảng


133

Tôi đang cố gắng sử dụng .distotype trong Linq để nhận kết quả dựa trên một trường của bảng (vì vậy không yêu cầu toàn bộ các bản ghi trùng lặp từ bảng).

Tôi biết viết truy vấn cơ bản bằng cách sử dụng riêng biệt như sau:

var query = (from r in table1
orderby r.Text
select r).distinct();

nhưng tôi cần kết quả r.textkhông trùng lặp.


Bạn cần chỉ định trường nào bạn muốn khác biệt, xem msdn.microsoft.com/en-us/l
Library / bb348436.aspx

Câu trả lời:


300

Thử cái này:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());

Điều này sẽ nhóm bảng theo Textvà sử dụng hàng đầu tiên từ mỗi nhóm dẫn đến các hàng Textkhác biệt.


2
Điều gì xảy ra nếu nhóm có nhiều hơn 1 lĩnh vực?

6
@ user585440: Trong trường hợp đó, bạn sử dụng một loại ẩn danh như vậy:table1.GroupBy(x => new { x.Text, x.Property2, x.Property3 }).Select(x => x.First());
Daniel Hilgarth

2
Vâng, bạn đúng và tôi đã tìm thấy nó. Dẫu sao cũng xin cảm ơn. Và tôi cũng thấy rằng Chọn (x => x.First ()) có thể gây ra sự cố. Tốt hơn là thay đổi thành Chọn (x => x.FirstOrDefault ());

6
Tôi đã phải sử dụng FirstOrDefault nếu không có lỗi thời gian chạy
TruthOf42

2
@ TruthOf42 Điều đó khá khó xảy ra. GroupBykhông tạo các nhóm trống, xem bình luận trước của tôi. Rất có thể, mã của bạn chứa nhiều hơn những gì bạn thấy ở đây. Có lẽ bạn có một Wherehoặc là một điều kiện cho First.
Daniel Hilgarth

26

MoreLinq có DistinctBy phương pháp mà bạn có thể sử dụng:

Nó sẽ cho phép bạn làm:

var results = table1.DistictBy(row => row.Text);

Việc thực hiện phương thức (thiếu xác thực đối số) như sau:

private static IEnumerable<TSource> DistinctByImpl<TSource, TKey>(IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
    HashSet<TKey> knownKeys = new HashSet<TKey>(comparer);
    foreach (TSource element in source)
    {
        if (knownKeys.Add(keySelector(element)))
        {
            yield return element;
        }
    }
}

xin lỗi tôi không thích sử dụng EqualityComparer.
Megha Jain

@MeghaJain Vâng, một cái sẽ được sử dụng bất kể, khi nào cũng GroupBycần. Cả hai phương pháp sẽ sử dụng mặc định EqualityComparernếu không được cung cấp.
Phục vụ

9
Vâng, sửa tôi nếu tôi sai, nhưng điều này khác biệt ở đây được thực hiện trong bộ nhớ, không phải trong DB? Điều này không thể dẫn đến quét toàn bộ không mong muốn?
Kek

@Kek. Không, vì lợi nhuận mang lại, bạn sẽ dừng lại ở yếu tố khác biệt đầu tiên. Cuối cùng, vâng, bạn sẽ tải từng khóa vào Hashset, nhưng vì nó không thể truy cập được và có thể hiểu được, bạn sẽ chỉ nhận được các mục đó. Nếu bạn đang nói về LINQ to SQL, thì có, điều này sẽ thực hiện quét bảng.
PRman

12

nhưng tôi cần kết quả trong đó r.text không bị trùng lặp

Âm thanh như thể bạn muốn điều này:

table1.GroupBy(x => x.Text)
      .Where(g => g.Count() == 1)
      .Select(g => g.First());

Điều này sẽ chọn các hàng trong đó Textlà duy nhất.


7

Câu trả lời của Daniel Hilgarth ở trên dẫn đến một System.NotSupportedngoại lệ với Entity-Framework . Với Entity-Framework , nó phải là:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());

3

Có rất nhiều cuộc thảo luận xung quanh chủ đề này.

Bạn có thể tìm thấy một trong số họ ở đây :

Một trong những gợi ý phổ biến nhất là phương pháp Phân biệt lấy biểu thức lambda làm tham số như @Servy đã chỉ ra.

Kiến trúc sư trưởng của C #, Anders Hejlsberg đã đề xuất giải pháp ở đây . Cũng giải thích lý do tại sao nhóm thiết kế khung đã quyết định không thêm quá tải phương thức Phân biệt mà mất một lambda.


2

Từ những gì tôi đã tìm thấy, truy vấn của bạn chủ yếu là chính xác. Chỉ cần thay đổi "select r" thành "select r.Text" là tất cả và điều đó sẽ giải quyết vấn đề. Đây là cách MSDN ghi lại cách nó hoạt động.

Ví dụ:

    var query = (from r in table1 orderby r.Text select r.Text).distinct();

bạn đã thay đổi câu lệnh "select" có thể không mong muốn trong trường hợp này
faza

1
data.Select(x=>x.Name).Distinct().Select(x => new SelectListItem { Text = x });

-2

thử mã này:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());

-5

Bạn có thể thử điều này:table1.GroupBy(t => t.Text).Select(shape => shape.r)).Distinct();

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.