truy vấn linq để trả về các giá trị trường riêng biệt từ danh sách các đối tượng


88
class obj
{
    int typeId; //10 types  0-9 
    string uniqueString; //this is unique
}

Giả sử có danh sách với 100 phần tử của obj, nhưng chỉ có 10 typeID duy nhất.
Có thể viết một truy vấn LINQ trả về 10 int duy nhất từ ​​danh sách đối tượng không?


Câu hỏi này quá dễ và không phù hợp với tiền thưởng.
Thinker

Câu trả lời:


155
objList.Select(o=>o.typeId).Distinct()

2
Dạng thứ hai dường như sử dụng quá nhiều Distinction không tồn tại theo như tôi biết.
Jon Skeet

Rất tiếc, đã xóa cái thứ hai, cảm ơn @Jon Skeet, điều đó có thể được thực hiện với IEqualityComparer
Arsen Mkrtchyan

3
Như Jon Skeet đã đề cập, điều này sẽ chỉ trả về các thuộc tính được chỉ định trong Lựa chọn.
Peet vd Westhuizen

58

Giả sử bạn muốn đối tượng đầy đủ, nhưng chỉ muốn xử lý sự khác biệt bằng cách typeID, không có gì được tích hợp trong LINQ để làm cho điều này dễ dàng. (Nếu bạn chỉ muốn các typeIDgiá trị, thật dễ dàng - chiếu vào đó Selectvà sau đó sử dụng lệnh Distinctgọi bình thường .)

Trong MoreLINQ, chúng tôi có DistinctBytoán tử mà bạn có thể sử dụng:

var distinct = list.DistinctBy(x => x.typeID);

Tuy nhiên, điều này chỉ hoạt động đối với LINQ to Object.

Bạn có thể sử dụng nhóm hoặc tra cứu, nó chỉ hơi khó chịu và không hiệu quả:

var distinct = list.GroupBy(x => x.typeID, (key, group) => group.First());

Để có DistinctBy xuất hiện bạn cần phải thêm Microsoft.Ajax.Utilities namespace
Shiljo Paulson

1
@Shil: Không, tôi đang viết về DistinctBy trong MoreLINQ. Không liên quan gì đến Microsoft.Ajax.Utilities.
Jon Skeet

Bây giờ tôi có thể thấy có một tình trạng quá tải của biệt trong LINQ mà lấy một IEqualityComparer như tham số và trả về một danh sách các đối tượng khác nhau tùy thuộc vào việc thực hiện các phương pháp trong IEqualityComparer
Dipendu Paul

1
@DipenduPaul: Có, nhưng điều đó vẫn có nghĩa là tạo một trình so sánh bình đẳng cho một thuộc tính nhất định, điều này gây phiền nhiễu và khó đọc hơn. Nếu bạn có thể sử dụng phụ thuộc MoreLINQ, tôi nghĩ điều đó rõ ràng hơn.
Jon Skeet

22

Nếu chỉ muốn sử dụng Linq thuần túy, bạn có thể sử dụng groupby:

List<obj> distinct =
  objs.GroupBy(car => car.typeID).Select(g => g.First()).ToList();

Nếu bạn muốn một phương thức được sử dụng trên toàn ứng dụng, tương tự như những gì MoreLinq làm:

public static IEnumerable<TSource> DistinctBy<TSource, TKey>
    (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> seenKeys = new HashSet<TKey>();
    foreach (TSource element in source)
    {
        if (!seenKeys.Contains(keySelector(element)))
        {
            seenKeys.Add(keySelector(element));
            yield return element;
        }
    }
}

Sử dụng phương pháp này để tìm các giá trị riêng biệt chỉ bằng thuộc tính Id, bạn có thể sử dụng:

var query = objs.DistinctBy(p => p.TypeId);

bạn có thể sử dụng nhiều thuộc tính:

var query = objs.DistinctBy(p => new { p.TypeId, p.Name });

Cảm ơn phần nhiều thuộc tính !
Nae

7

Chắc chắn, sử dụng Enumerable.Distinct.

Với một bộ sưu tập obj(ví dụ foo), bạn sẽ làm như sau:

var distinctTypeIDs = foo.Select(x => x.typeID).Distinct();

5

Tôi nghĩ đây là những gì bạn đang tìm kiếm:

    var objs= (from c in List_Objects 
orderby c.TypeID  select c).GroupBy(g=>g.TypeID).Select(x=>x.FirstOrDefault());      

Tương tự với điều này Trả lại một IQueryable với LINQ?


.Firstcũng được, vì bạn sẽ không có nhóm nếu không có thứ gì đó trong đó.
mqp

1
Bạn có thể sử dụng quá tải thay thế GroupByđể làm cho việc này đơn giản hơn - hãy xem câu trả lời của tôi để làm ví dụ.
Jon Skeet

3

Nếu chỉ muốn sử dụng Linq, bạn có thể ghi đè các phương thức EqualsGetHashCode .

Loại sản phẩm :

public class Product
{
    public string ProductName { get; set; }
    public int Id { get; set; }


    public override bool Equals(object obj)
    {
        if (!(obj is Product))
        {
            return false;
        }

        var other = (Product)obj;
        return Id == other.Id;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

Phương pháp chính :

static void Main(string[] args)
    {

        var products = new List<Product>
        {
            new Product{ ProductName="Product 1",Id = 1},
            new Product{ ProductName="Product 2",Id = 2},
            new Product{ ProductName="Product 4",Id = 5},
            new Product{ ProductName="Product 3",Id = 3},
            new Product{ ProductName="Product 4",Id = 4},
            new Product{ ProductName="Product 6",Id = 4},
            new Product{ ProductName="Product 6",Id = 4},
        };

        var itemsDistinctByProductName = products.Distinct().ToList();

        foreach (var product in itemsDistinctByProductName)
        {
            Console.WriteLine($"Product Id : {product.Id} ProductName : {product.ProductName} ");
        }

        Console.ReadKey();
    }

1

Tôi muốn liên kết một dữ liệu cụ thể với menu thả xuống và nó phải khác biệt. Tôi đã làm như sau:

List<ClassDetails> classDetails;
List<string> classDetailsData = classDetails.Select(dt => dt.Data).Distinct.ToList();
ddlData.DataSource = classDetailsData;
ddlData.Databind();

Xem nếu nó giúp

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.