Bir nesne listesinden farklı alan değerleri döndürmek için linq sorgusu


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

100 obj öğesi içeren bir liste olduğunu, ancak yalnızca 10 benzersiz typeID olduğunu varsayalım.
Nesneler listesinden 10 benzersiz girişi döndüren bir LINQ sorgusu yazmak mümkün müdür?


Bu soru çok kolay ve ödül için uygun değil.
Thinker

Yanıtlar:


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

2
İkinci form, bildiğim kadarıyla var olmayan bir Distinct aşırı yüklemesini kullanıyor gibi görünüyor.
Jon Skeet

Oops, ikincisini kaldırdı, teşekkürler @Jon Skeet, IEqualityComparer ile yapılabilir
Arsen Mkrtchyan

3
Jon Skeet'in bahsettiği gibi, bu yalnızca Select'te belirtilen özellikleri döndürecektir.
Peet vd Westhuizen

59

Tüm nesneyi istediğinizi, ancak yalnızca farklılıkla başa çıkmak istediğinizi varsayarsak, typeIDLINQ'da bunu kolaylaştıracak hiçbir şey yoktur. ( SadecetypeID değerleri istiyorsanız, kolaydır - bunu ile yansıtın Selectve sonra normal Distinctaramayı kullanın .)

In MoreLINQ Elimizdeki DistinctByşunu kullanabilirsiniz operatörünü:

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

Bu yalnızca LINQ to Objects için çalışır.

Bir gruplama veya arama kullanabilirsiniz, bu biraz can sıkıcı ve verimsizdir:

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

DistinctBy sahip olmak size ad Microsoft.Ajax.Utilities eklemeniz gerekir görünmesini
Shiljo Paulson

1
@Shil: Hayır, MoreLINQ'da DistinctBy hakkında yazıyordum. Microsoft.Ajax.Utilities ile ilgisi yok.
Jon Skeet

Şimdi
LINQ'da

1
@DipenduPaul: Evet, ancak bu yine de belirli bir mülk için bir eşitlik karşılaştırıcısı oluşturmak anlamına geliyor, bu can sıkıcı ve okumayı zorlaştırıyor. MoreLINQ bağımlılığını alabilirseniz, bence bu daha temiz.
Jon Skeet

27

Sadece saf Linq kullanmak istiyorsanız, groupby'yi kullanabilirsiniz:

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

MoreLinq'in yaptığına benzer şekilde uygulamanın tamamında bir yöntemin kullanılmasını istiyorsanız :

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;
        }
    }
}

Yalnızca Id özelliğini kullanarak farklı değerleri bulmak için bu yöntemi kullanarak şunları kullanabilirsiniz:

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

birden çok özelliği kullanabilirsiniz:

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

Birden çok özellik bölümü için teşekkürler !
Nae

7

Elbette, kullan Enumerable.Distinct.

Bir koleksiyon verildiğinde obj(örneğin foo), şöyle bir şey yaparsınız:

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

5

Sanırım aradığınız şey bu:

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

Buna benzer LINQ ile Farklı Bir IQueryable Döndürmek?


.Firstiyi, çünkü içinde bir şey olmasa gruba sahip olmayacaksın.
mqp

1
Bunu da GroupBydaha basit hale getirmek için alternatif bir aşırı yükleme kullanabilirsiniz - örnek için cevabıma bakın.
Jon Skeet

3

Sadece Linq kullanmak istiyorsanız, Eşittir ve GetHashCode yöntemlerini geçersiz kılabilirsiniz .

Ürün sınıfı:

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();
    }
}

Ana Yöntem:

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

Belirli bir veriyi açılır menüye bağlamak istedim ve farklı olması gerekiyor. Ben şunları yaptım:

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

Yardımcı olup olmadığına bakın

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.