Ich habe die folgende EF-Klasse aus einer Datenbank abgeleitet (vereinfacht)
class Product
{
public string ProductId;
public string ProductName;
public string CategoryId;
public string CategoryName;
}
ProductId
ist der Primärschlüssel der Tabelle.
Für eine schlechte Entwurfsentscheidung des DB-Designers (ich kann sie nicht ändern) habe ich CategoryId
und CategoryName
in dieser Tabelle.
Ich benötige eine DropDownList mit (eindeutig) CategoryId
als Wert und CategoryName
als Text . Deshalb habe ich folgenden Code angewendet:
product.Select(m => new {m.CategoryId, m.CategoryName}).Distinct();
logischerweise sollte ein anonymes Objekt mit CategoryId
und CategoryName
als Eigenschaften erstellt werden. Das Distinct()
garantiert, dass es keine doppelten Paare gibt ( CategoryId
, CategoryName
).
Aber eigentlich funktioniert es nicht. Soweit ich verstanden habe, Distinct()
funktionieren die Werke nur, wenn es nur ein Feld in der Sammlung gibt, sonst werden sie einfach ignoriert ... ist es richtig? Gibt es eine Problemumgehung? Vielen Dank!
AKTUALISIEREN
Entschuldigung product
ist:
List<Product> product = new List<Product>();
Ich habe einen alternativen Weg gefunden, um das gleiche Ergebnis zu erzielen wie Distinct()
:
product.GroupBy(d => new {d.CategoryId, d.CategoryName})
.Select(m => new {m.Key.CategoryId, m.Key.CategoryName})
Antworten:
Ich gehe davon aus, dass Sie eine bestimmte Methode wie einen Methodenaufruf für eine Liste verwenden. Sie müssen das Ergebnis der Abfrage als Datenquelle für Ihre DropDownList verwenden, indem Sie es beispielsweise über materialisieren
ToList
.var distinctCategories = product .Select(m => new {m.CategoryId, m.CategoryName}) .Distinct() .ToList(); DropDownList1.DataSource = distinctCategories; DropDownList1.DataTextField = "CategoryName"; DropDownList1.DataValueField = "CategoryId";
Eine andere Möglichkeit, wenn Sie die realen Objekte anstelle des anonymen Typs mit nur wenigen Eigenschaften benötigen, ist die Verwendung
GroupBy
mit einem anonymen Typ:List<Product> distinctProductList = product .GroupBy(m => new {m.CategoryId, m.CategoryName}) .Select(group => group.First()) // instead of First you can also apply your logic here what you want to take, for example an OrderBy .ToList();
Eine dritte Option ist die Verwendung von MoreLinqs
DistinctBy
.quelle
Equals
+ überschreiben,GetHashCode
oder Sie müssenIEQualityCpomparer<TypeName>
bei der Überladung von einen benutzerdefinierten Typ angebenDistinct
.- genau das
Anonyme Typen 'magisch' implementieren
Equals
undGetHashcode
Ich gehe irgendwo von einem anderen Fehler aus. Groß- und Kleinschreibung beachten? Veränderbare Klassen? Nicht vergleichbare Felder?
quelle
Die Distinct- Methode gibt verschiedene Elemente aus einer Sequenz zurück.
Wenn Sie sich die Implementierung mit Reflector ansehen, werden Sie feststellen, dass sie
DistinctIterator
für Ihren anonymen Typ erstellt wird. Ein eindeutiger Iterator fügt Elemente hinzu,Set
wenn über die Sammlung aufgezählt wird. Dieser Enumerator überspringt alle Elemente, die bereits vorhanden sindSet
.Set
VerwendungenGetHashCode
undEquals
Methoden zum Definieren, ob das Element bereits in vorhanden istSet
.Wie
GetHashCode
undEquals
für anonymen Typ implementiert? Wie auf msdn angegeben :Sie sollten also auf jeden Fall unterschiedliche anonyme Objekte haben, wenn Sie eine bestimmte Sammlung durchlaufen. Das Ergebnis hängt nicht davon ab, wie viele Felder Sie für Ihren anonymen Typ verwenden.
quelle
Verwenden Sie das
Key
Schlüsselwort in Ihrer Auswahl, wie unten beschrieben.product.Select(m => new {Key m.CategoryId, Key m.CategoryName}).Distinct();
Mir ist klar, dass dies einen alten Thread aufwirft, aber ich dachte, es könnte einigen Leuten helfen. Ich codiere im Allgemeinen in VB.NET, wenn ich mit .NET arbeite, daher
Key
kann es sein, dass es anders in C # übersetzt wird.quelle
Beantwortung der Überschrift der Frage (was die Leute hier angezogen hat) und Ignorieren, dass im Beispiel anonyme Typen verwendet wurden ....
Diese Lösung funktioniert auch für nicht anonyme Typen. Es sollte nicht für anonyme Typen benötigt werden.
Hilfsklasse:
/// <summary> /// Allow IEqualityComparer to be configured within a lambda expression. /// From /programming/98033/wrap-a-delegate-in-an-iequalitycomparer /// </summary> /// <typeparam name="T"></typeparam> public class LambdaEqualityComparer<T> : IEqualityComparer<T> { readonly Func<T, T, bool> _comparer; readonly Func<T, int> _hash; /// <summary> /// Simplest constructor, provide a conversion to string for type T to use as a comparison key (GetHashCode() and Equals(). /// /programming/98033/wrap-a-delegate-in-an-iequalitycomparer, user "orip" /// </summary> /// <param name="toString"></param> public LambdaEqualityComparer(Func<T, string> toString) : this((t1, t2) => toString(t1) == toString(t2), t => toString(t).GetHashCode()) { } /// <summary> /// Constructor. Assumes T.GetHashCode() is accurate. /// </summary> /// <param name="comparer"></param> public LambdaEqualityComparer(Func<T, T, bool> comparer) : this(comparer, t => t.GetHashCode()) { } /// <summary> /// Constructor, provide a equality comparer and a hash. /// </summary> /// <param name="comparer"></param> /// <param name="hash"></param> public LambdaEqualityComparer(Func<T, T, bool> comparer, Func<T, int> hash) { _comparer = comparer; _hash = hash; } public bool Equals(T x, T y) { return _comparer(x, y); } public int GetHashCode(T obj) { return _hash(obj); } }
Einfachste Verwendung:
List<Product> products = duplicatedProducts.Distinct( new LambdaEqualityComparer<Product>(p => String.Format("{0}{1}{2}{3}", p.ProductId, p.ProductName, p.CategoryId, p.CategoryName)) ).ToList();
Die einfachste (aber nicht so effiziente) Verwendung besteht darin, einer Zeichenfolgendarstellung zuzuordnen, damit benutzerdefiniertes Hashing vermieden wird. Gleiche Zeichenfolgen haben bereits gleiche Hash-Codes.
Referenz:
Wickeln Sie einen Delegaten in einen IEqualityComparer
quelle
Dies ist meine Lösung, sie unterstützt keySelectors verschiedener Typen:
public static IEnumerable<TSource> DistinctBy<TSource>(this IEnumerable<TSource> source, params Func<TSource, object>[] keySelectors) { // initialize the table var seenKeysTable = keySelectors.ToDictionary(x => x, x => new HashSet<object>()); // loop through each element in source foreach (var element in source) { // initialize the flag to true var flag = true; // loop through each keySelector a foreach (var (keySelector, hashSet) in seenKeysTable) { // if all conditions are true flag = flag && hashSet.Add(keySelector(element)); } // if no duplicate key was added to table, then yield the list element if (flag) { yield return element; } } }
Um es zu benutzen:
quelle
public List<ItemCustom2> GetBrandListByCat(int id) { var OBJ = (from a in db.Items join b in db.Brands on a.BrandId equals b.Id into abc1 where (a.ItemCategoryId == id) from b in abc1.DefaultIfEmpty() select new { ItemCategoryId = a.ItemCategoryId, Brand_Name = b.Name, Brand_Id = b.Id, Brand_Pic = b.Pic, }).Distinct(); List<ItemCustom2> ob = new List<ItemCustom2>(); foreach (var item in OBJ) { ItemCustom2 abc = new ItemCustom2(); abc.CategoryId = item.ItemCategoryId; abc.BrandId = item.Brand_Id; abc.BrandName = item.Brand_Name; abc.BrandPic = item.Brand_Pic; ob.Add(abc); } return ob; }
quelle
Die Lösung für Ihr Problem sieht folgendermaßen aus:
public class Category { public long CategoryId { get; set; } public string CategoryName { get; set; } }
...
public class CategoryEqualityComparer : IEqualityComparer<Category> { public bool Equals(Category x, Category y) => x.CategoryId.Equals(y.CategoryId) && x.CategoryName .Equals(y.CategoryName, StringComparison.OrdinalIgnoreCase); public int GetHashCode(Mapping obj) => obj == null ? 0 : obj.CategoryId.GetHashCode() ^ obj.CategoryName.GetHashCode(); }
...
var distinctCategories = product .Select(_ => new Category { CategoryId = _.CategoryId, CategoryName = _.CategoryName }) .Distinct(new CategoryEqualityComparer()) .ToList();
quelle
Employee emp1 = new Employee() { ID = 1, Name = "Narendra1", Salary = 11111, Experience = 3, Age = 30 };Employee emp2 = new Employee() { ID = 2, Name = "Narendra2", Salary = 21111, Experience = 10, Age = 38 }; Employee emp3 = new Employee() { ID = 3, Name = "Narendra3", Salary = 31111, Experience = 4, Age = 33 }; Employee emp4 = new Employee() { ID = 3, Name = "Narendra4", Salary = 41111, Experience = 7, Age = 33 }; List<Employee> lstEmployee = new List<Employee>(); lstEmployee.Add(emp1); lstEmployee.Add(emp2); lstEmployee.Add(emp3); lstEmployee.Add(emp4); var eemmppss=lstEmployee.Select(cc=>new {cc.ID,cc.Age}).Distinct();
quelle