Antworten:
Versuchen Sie, sich durch mehr als ein Feld zu unterscheiden? Wenn ja, verwenden Sie einfach einen anonymen Typ und den Operator Distinct und es sollte in Ordnung sein:
var query = doc.Elements("whatever")
.Select(element => new {
id = (int) element.Attribute("id"),
category = (int) element.Attribute("cat") })
.Distinct();
Wenn Sie versuchen, eine bestimmte Menge von Werten eines "größeren" Typs zu erhalten, aber nur eine Teilmenge von Eigenschaften für den Unterscheidungsaspekt betrachten, möchten Sie wahrscheinlich, DistinctBy
wie in MoreLINQ implementiert in DistinctBy.cs
:
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
this 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;
}
}
}
(Wenn Sie null
als Vergleicher übergeben, wird der Standardvergleicher für den Schlüsseltyp verwendet.)
Verwenden Sie das einfach Distinct()
mit Ihrem eigenen Vergleicher.
Zusätzlich zu Jon Skeets Antwort können Sie die Gruppe auch nach Ausdrücken verwenden, um die eindeutigen Gruppen mit einer Anzahl für jede Gruppeniteration zu ermitteln:
var query = from e in doc.Elements("whatever")
group e by new { id = e.Key, val = e.Value } into g
select new { id = g.Key.id, val = g.Key.val, count = g.Count() };
Für jeden, der noch sucht; Hier ist eine andere Möglichkeit, einen benutzerdefinierten Lambda-Vergleicher zu implementieren.
public class LambdaComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> _expression;
public LambdaComparer(Func<T, T, bool> lambda)
{
_expression = lambda;
}
public bool Equals(T x, T y)
{
return _expression(x, y);
}
public int GetHashCode(T obj)
{
/*
If you just return 0 for the hash the Equals comparer will kick in.
The underlying evaluation checks the hash and then short circuits the evaluation if it is false.
Otherwise, it checks the Equals. If you force the hash to be true (by assuming 0 for both objects),
you will always fall through to the Equals check which is what we are always going for.
*/
return 0;
}
}
Sie können dann eine Erweiterung für den linq Distinct erstellen, die Lambdas aufnehmen kann
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> list, Func<T, T, bool> lambda)
{
return list.Distinct(new LambdaComparer<T>(lambda));
}
Verwendung:
var availableItems = list.Distinct((p, p1) => p.Id== p1.Id);
Ich bin etwas spät bei der Antwort, aber Sie können dies tun, wenn Sie das gesamte Element und nicht nur die Werte, nach denen Sie gruppieren möchten, möchten:
var query = doc.Elements("whatever")
.GroupBy(element => new {
id = (int) element.Attribute("id"),
category = (int) element.Attribute("cat") })
.Select(e => e.First());
Auf diese Weise erhalten Sie das erste vollständige Element, das Ihrer Gruppe nach Auswahl entspricht, ähnlich wie im zweiten Beispiel von Jon Skeets mit DistinctBy, jedoch ohne den IEqualityComparer-Vergleicher zu implementieren. DistinctBy wird höchstwahrscheinlich schneller sein, aber die obige Lösung wird weniger Code beinhalten, wenn die Leistung kein Problem darstellt.
// First Get DataTable as dt
// DataRowComparer Compare columns numbers in each row & data in each row
IEnumerable<DataRow> Distinct = dt.AsEnumerable().Distinct(DataRowComparer.Default);
foreach (DataRow row in Distinct)
{
Console.WriteLine("{0,-15} {1,-15}",
row.Field<int>(0),
row.Field<string>(1));
}
Da es darum geht, jedes Element genau einmal zu haben, ist eine "Menge" für mich sinnvoller.
Beispiel mit implementierten Klassen und IEqualityComparer:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Product(int x, string y)
{
Id = x;
Name = y;
}
}
public class ProductCompare : IEqualityComparer<Product>
{
public bool Equals(Product x, Product y)
{ //Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the products' properties are equal.
return x.Id == y.Id && x.Name == y.Name;
}
public int GetHashCode(Product product)
{
//Check whether the object is null
if (Object.ReferenceEquals(product, null)) return 0;
//Get hash code for the Name field if it is not null.
int hashProductName = product.Name == null ? 0 : product.Name.GetHashCode();
//Get hash code for the Code field.
int hashProductCode = product.Id.GetHashCode();
//Calculate the hash code for the product.
return hashProductName ^ hashProductCode;
}
}
Jetzt
List<Product> originalList = new List<Product> {new Product(1, "ad"), new Product(1, "ad")};
var setList = new HashSet<Product>(originalList, new ProductCompare()).ToList();
setList
wird einzigartige Elemente haben
Ich dachte daran, während ich mich damit befasste, .Except()
was einen Satzunterschied ergibt