class obj
{
int typeId; //10 types 0-9
string uniqueString; //this is unique
}
Załóżmy, że istnieje lista zawierająca 100 elementów obj, ale tylko 10 unikalnych identyfikatorów typów.
Czy można napisać zapytanie LINQ, które zwróci 10 unikatowych liczb całkowitych z listy obiektów?
Odpowiedzi:
źródło
Zakładając, że chcesz mieć pełny obiekt, ale chcesz radzić sobie tylko z odrębnością
typeID
, nie ma nic wbudowanego w LINQ, aby to ułatwić. (Jeśli tylko chcesz, abytypeID
wartości, to proste - projekt, który zSelect
, a następnie użyć normalnejDistinct
rozmowy).W MoreLINQ mamy
DistinctBy
operator, którego możesz użyć:var distinct = list.DistinctBy(x => x.typeID);
Działa to tylko w przypadku LINQ to Objects.
Możesz użyć grupowania lub wyszukiwania, jest to trochę denerwujące i nieefektywne:
var distinct = list.GroupBy(x => x.typeID, (key, group) => group.First());
źródło
Jeśli chcesz tylko użyć czystego Linq, możesz użyć groupby:
Jeśli chcesz, aby metoda była używana w całej aplikacji, podobnie jak robi to MoreLinq :
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; } } }
Korzystając z tej metody, aby znaleźć różne wartości przy użyciu tylko właściwości Id, możesz użyć:
var query = objs.DistinctBy(p => p.TypeId);
możesz użyć wielu właściwości:
var query = objs.DistinctBy(p => new { p.TypeId, p.Name });
źródło
Jasne, użyj
Enumerable.Distinct
.Biorąc pod uwagę kolekcję
obj
(np.foo
), Zrobiłbyś coś takiego:var distinctTypeIDs = foo.Select(x => x.typeID).Distinct();
źródło
Myślę, że tego właśnie szukasz:
var objs= (from c in List_Objects orderby c.TypeID select c).GroupBy(g=>g.TypeID).Select(x=>x.FirstOrDefault());
Podobnie do tego zwracania wyróżniającego się IQueryable z LINQ?
źródło
.First
jest w porządku, ponieważ nie miałbyś grupy, gdyby czegoś w niej nie było.GroupBy
aby to uprościć - zobacz przykład w mojej odpowiedzi.Jeśli chcesz tylko użyć Linq, możesz przesłonić metody Equals i GetHashCode .
Klasa produktu :
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(); } }
Główna metoda:
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(); }
źródło
Chciałem powiązać określone dane z menu rozwijanym i powinno być odrębne. Zrobiłem co następuje:
List<ClassDetails> classDetails; List<string> classDetailsData = classDetails.Select(dt => dt.Data).Distinct.ToList(); ddlData.DataSource = classDetailsData; ddlData.Databind();
Zobacz, czy to pomaga
źródło