I have an object called "response" that is type: <LabelResponse> that contains an object called "items" that is type: IEnumerable<PostLabelResponse>. This PostLabelResponse contains 2 strings called "Key" and "Category". The IEnumerable contains duplicated values of this PostLabelResponse. How can i delete this duplicates by the value "Key" and return the "response"?
I tried with response.items.Distinct() of LinQ but it didn´t work
CodePudding user response:
It seems, that your current PostLabelResponse which I assume being something like this
public class PostLabelResponse {
...
public string Key {get; set;}
public string Value {get; set;}
...
}
doesn't doesn't provide custom Equals and GetHashCode method and
that's why .Net uses default ones (which compare references not values).
If you want to compare values, say, Key and not Value, you can either implement Equals and GetHashCode:
public class PostLabelResponse {
public string Key { get; set; }
public string Value { get; set; }
...
public override bool Equals(object obj) {
if (ReferenceEquals(this, obj))
return true;
return obj is PostLabelResponse other &&
Key == other.Key;
}
public override int GetHashCode() =>
Key?.GetHashCode() ?? 0;
}
From now on Distinct() starts using your rules (Equals and GetHashCode). Or you can implement a custom comparer:
public sealed class MyComparer : IEqualityComparer<PostLabelResponse> {
public bool Equals(PostLabelResponse x, PostLabelResponse y) {
if (ReferenceEquals(x, y))
return true;
if (null == x || null == y)
return false;
return (x.Key == y.Key);
}
public int GetHashCode(PostLabelResponse obj) {
return obj?.Key?.GetHashCode() ?? 0;
}
}
which you should specify when using Distinct:
.Distinct(new MyComparer())
CodePudding user response:
.NET 6 introduced the DistinctBy method that can be used to find duplicates based on specific properties instead of the entire object. In previous versions, the same method is available in the MoreLINQ library. You can add the NuGet package, but the operator is so small you could easily add it to your project as source.
Assuming your class is :
public class PostLabelResponse {
...
public string Key {get; set;}
public string Value {get; set;}
...
}
You can retrieve distinct objects with :
var distinct=response.items.DistinctBy(x=>x.Key);
The operator code is really short :
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IEqualityComparer<TKey>? comparer=null)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
return _(); IEnumerable<TSource> _()
{
var knownKeys = new HashSet<TKey>(comparer);
foreach (var element in source)
{
if (knownKeys.Add(keySelector(element)))
yield return element;
}
}
}
