I was thinking about writing generic functions for basic Math operations such as Min, Max etc.
But i i dont know how to compare two generic types :
public T Max<T>(T v1, T v2) where T: struct
{
return (v1 > v2 ? v1 : v2);
}
How about that?
Thank you.
You probably want to constrain the generic types to implement IComparable:
public T Max<T>(T v1, T v2) where T: struct, IComparable<T>
and then use the CompareTo method:
{
return (v1.CompareTo(v2) > 0 ? v1 : v2);
}
If you only want to create comparison functions then you could use the default comparer for the type T. For example:
public static T Max<T>(T x, T y)
{
return (Comparer<T>.Default.Compare(x, y) > 0) ? x : y;
}
If T implements IComparable<T> then that comparer will be used; if T doesn't implement IComparable<T> but does implement IComparable then that comparer will be used; if T doesn't implement either IComparable<T> or IComparable then a runtime exception will be thrown.
If you want/need to do more than just compare the items then you could have a look at the generic operators implementation in MiscUtil and the related article.
Let me disagree.
The #LukeH's implementation is not Generic.
I will explain why it is not Generic:
Comparer<T>.Default involves inspecting T at run-time to determine if it implements IComparable<T>, IComparable or neither.
Although this behavior is not well documented in http://msdn.microsoft.com/en-us/library/azhsac5f.aspx, we can deduct it because Comparer<T>.Default throws an exception when T does not implement neither. If the inspection was done at compilation-time there would be no need for an exception (runtime), with an compile-time error would suffice.
Then, as Comparer<T>.Default uses Reflection, this means a high cost on Run-Time, then...., It is NOT Generic... Why?
Because Generic Programming means: A single algorithm (Generic) can cover many implementations (for many types) maintaining efficiency of hand-written versions.
Take an example. The handwritten version for integers would be:
public static int Max( int x, int y)
{
return (x.CompareTo(y) > 0) ? x : y;
}
It is very simple, involving only a comparison (or maybe more, depending on how Int32.CompareTo() is implemented).
If we use the #LukeH's implementation, we are adding Reflection to something that is very simple.
In short:
Always prefer Compilation-time errors to Run-Time Exceptions ( this is not Javascript, Ruby,... :-) )
This implementation is less efficient compared to the handwritten version (for any type)
On the other hand.
What do you think Max should return when x and y are equivalents?
I'm starting to analyze Real-Generic implementations....
The ideal implementation would be something like...
public static T Max<T>(T x, T y, Func<T, T, int> cmp)
{
return (cmp(x, y) > 0) ? x : y;
}
//Pseudo-code ( note the 'or' next to 'where' )
public static T Max<T>(T x, T y) where T: IComparable<T> or IComparable
{
return Max(x, y, (a, b) => { return a.CompareTo(b); });
}
This is not possible in C#, the next try is could be...
//pseudo-code
public static T Max<T>(T x, T y, Func<T, T, int> cmp)
{
return (cmp(x, y) > 0) ? x : y;
}
public static T Max<T>(T x, T y) where T: IComparable<T>
{
return Max(x, y, (a, b) => { return a.CompareTo(b); });
}
public static T Max<T>(T x, T y) where T: IComparable
{
return Max(x, y, (a, b) => { return a.CompareTo(b); });
}
But, this is neither possible, because overload resolution doesn't takes into account Generics Constraints....
Then, I'll leave out IComparable consciously. I'm just going to worry about IComparable<T>
public static T Max<T>(T x, T y, Func<T, T, int> cmp)
{
return (cmp(x, y) > 0) ? x : y;
}
public static T Max<T>(T x, T y) where T: IComparable<T>
{
return Max(x, y, (a, b) => { return a.CompareTo(b); });
}
This is a little too late, but why not use dynamic types and delegates as an alternative to IComparable? This way you get compile-type safety in most cases and will only get a runtime error when the types supplied both do not support the operator < and you fail to provide the default comparer as an argument.
public static T Max<T>(T first, T second, Func<T,T,bool> f = null)
{
Func<dynamic,dynamic,bool> is_left_smaller = (x, y) => x < y ? true : false;
var compare = f ?? new Func<T, T, bool>((x, y) => is_left_smaller(x, y));
return compare(first, second) ? second : first;
}
The solution I present on this answer would have worked (I actually did something like this) at the time the question was asked. I'm surprised no answer presents this alternative, thus I'll present it.
You can (and could have used back then) Linq.Expressions (Which was added in .NET 3.5, in 2007, making it a valid answer at the time of the question).
For starters:
using System.Linq.Expressions;
// ...
public T Max<T>(T v1, T v2)
{
var expression = Expression.GreaterThan
(
Expression.Constant(v1),
Expression.Constant(v2)
);
return Expression.Lambda<Func<bool>>(expression).Compile()() ? v1 : v2);
}
That has no need of dynamic, or Comparison<T>/IComparer<T>.
I believe that having a way to specify a custom comparison is better, but that is not what we are doing here. And of course, any type for which the presented solution works, Comparer<T>.Default would work. However, using Linq.Expressions would allow you implement any arithmetic operations. Take this as illustration of that approach.
There is, of course, overhead. Let us have a version that does compile to a function with parameters, we can think later about how to cache it:
using System.Linq.Expressions;
// ...
public T Max<T>(T v1, T v2)
{
var a = Expression.Parameter(typeof(int), "a");
var b = Expression.Parameter(typeof(int), "b");
var lambda = Expression.Lambda<Func<T, T, bool>>
(
Expression.GreaterThan(a, b),
new[]{a, b}
);
return ((Func<T, T, bool>)lambda.Compile())(v1, v2) ? v1 : v2;
}
Alright, to cache it, let us start with the generic class approach, which is easier to write:
using System.Linq.Expressions;
class GenericMath<T>
{
private static Func<T, T, bool>? _greaterThan;
public static Func<T, T, bool> GetGreaterThan()
{
if (_greaterThan == null)
{
var a = Expression.Parameter(typeof(int), "a");
var b = Expression.Parameter(typeof(int), "b");
var lambda = Expression.Lambda<Func<T, T, bool>>
(
Expression.GreaterThan(a, b),
new[]{a, b}
);
_greaterThan = (Func<T, T, bool>)lambda.Compile();
}
return _greaterThan;
}
public static T Max(T v1, T v2)
{
return GetGreaterThan()(v1, v2) ? v1 : v2;
}
}
Of course, statics on generics has drawbacks (there is a performance cost, plus the memory is never released). We can start our way to a better solution by using a dictionary cache instead:
using System.Linq.Expressions;
class GenericMath
{
private readonly static Dictionary<Type, Delegate> _gtCache = new Dictionary<Type, Delegate>();
public static Func<T, T, bool> GetGreaterThan<T>()
{
if (!_gtCache.TryGetValue(typeof(T), out var #delegate) || #delegate == null)
{
var a = Expression.Parameter(typeof(int), "a");
var b = Expression.Parameter(typeof(int), "b");
var lambda = Expression.Lambda<Func<T, T, bool>>
(
Expression.GreaterThan(a, b),
new[]{a, b}
);
#delegate = lambda.Compile();
_addCache[typeof(T)] = #delegate;
}
return (Func<T, T, bool>)#delegate;
}
public static T Max<T>(T v1, T v2)
{
return GetGreaterThan<T>()(v1, v2) ? v1 : v2;
}
}
Ok, I hear you, I have introduced a new problem: that solution is not thread-safe.
We could use ConcurrentDictionary (added in .NET 4.0, which -if I'm not mistaken- was on beta at the time of the question), but we would not be releasing memory anyway. Instead, we can make a custom class for this use:
public sealed class TypeCacheDict<TValue>
{
private const int Capacity = 256;
private readonly Entry[] _entries;
public TypeCacheDict()
{
_entries = new Entry[Capacity];
}
public TValue this[Type key]
{
get
{
if (TryGetValue(key, out var value))
{
return value;
}
throw new KeyNotFoundException();
}
set => Add(key, value);
}
public void Add(Type key, TValue value)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
var hash = key.GetHashCode();
var index = hash & (_entries.Length - 1);
var entry = _entries[index];
Thread.MemoryBarrier();
if (entry?.Hash != hash || !entry.Key.Equals(key))
{
Interlocked.Exchange(ref _entries[index], new Entry(hash, key, value));
}
}
public bool TryGetValue(Type key, out TValue value)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
var hash = key.GetHashCode();
var index = hash & (_entries.Length - 1);
var entry = _entries[index];
Thread.MemoryBarrier();
if (entry?.Hash == hash && entry.Key.Equals(key))
{
value = entry.Value;
return value != null;
}
value = default;
return false;
}
private sealed class Entry
{
internal readonly int Hash;
internal readonly Type Key;
internal readonly TValue Value;
internal Entry(int hash, Type key, TValue value)
{
Hash = hash;
Key = key;
Value = value;
}
}
}
This TypeCacheDict is thread-safe. First of all Entry is immutable. We don't need to worry about shared access to it. Plus, it a reference type, so replacing it is an atomic operation. We are using Thread.MemoryBarrier and Interlocked.Exchange o mimic Volatile.Read and Volatile.Write because Volatile was not available (and Thread.Volatile* lacks generic overload, and I would rather not instroduce extra casts).
With this new type we can now write:
private readonly static TypeCacheDict<Delegate> _gtCache = new TypeCacheDict<Delegate>();
The rest of the code could be left unchanged. Although there is room for improvement: TryGetOrAdd:
public TValue TryGetOrAdd(Type key, Func<TValue> valueFactory)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (valueFactory == null)
{
throw new ArgumentNullException(nameof(valueFactory));
}
var hash = key.GetHashCode();
var index = hash & (_entries.Length - 1);
var entry = _entries[index];
Thread.MemoryBarrier();
if (entry?.Hash == hash && entry.Key.Equals(key))
{
return entry.Value;
}
var value = valueFactory();
Interlocked.Exchange(ref _entries[index], new Entry(hash, key, value));
return value;
}
Which allows us to write:
public static Func<T, T, bool> GetGreaterThan<T>()
{
return (Func<T, T, bool>)_gtCache.TryGetOrAdd
(
typeof(T),
()=>
{
var a = Expression.Parameter(typeof(int), "a");
var b = Expression.Parameter(typeof(int), "b");
var lambda = Expression.Lambda<Func<T, T, bool>>(Expression.GreaterThan(a, b), new[]{a, b});
return lambda.Compile();
}
);
}
Of course, this is how you use it:
Console.WriteLine(GenericMath.Max<int>(90, 100)); // 100
To demostrate, the power of this approach, this is Add:
private readonly static TypeCacheDict<Delegate> _addCache = new TypeCacheDict<Delegate>();
public static Func<T, T, T> GetAdd<T>()
{
return (Func<T, T, T>)_addCache.TryGetOrAdd
(
typeof(T),
()=>
{
var a = Expression.Parameter(typeof(int), "a");
var b = Expression.Parameter(typeof(int), "b");
var lambda = Expression.Lambda<Func<T, T, T>>(Expression.Add(a,b), new[]{a, b});
return lambda.Compile();
}
);
}
public static T Add<T>(T v1, T v2)
{
return GetAdd<T>()(v1, v2);
}
And this is how you use it:
Console.WriteLine(GenericMath.Add<int>(90, 100)); // 190
.NET 7 introduces a new feature - generic math (read more here and here) which is based on addition of static abstract interface methods. This feature introduces a lot of interfaces which allow to generically abstract over number types and/or math operations, which allows to rewrite the function in question as:
public T Max<T>(T v1, T v2) where T: IComparisonOperators<T, T, bool> => v1 > v2 ? v1 : v2;
Note that for build-in number types usually you don't need to define your own Max because it is already defined on the INumber<T> interface:
public interface INumber<TSelf> :
// ... other interfaces,
System.Numerics.IComparisonOperators<TSelf,TSelf,bool>
// ... other interfaces
where TSelf : INumber<TSelf>
From memory, T also needs to be IComparable (add that to the where), and then you use v1.CompareTo(v2) > 0 etc.
Necromancing.
You can have a Max/Min function on an arbitrary number of parameters:
public static T Min<T>(params T[] source)
where T: struct, IComparable<T>
{
if (source == null)
throw new System.ArgumentNullException("source");
T value = default(T);
bool hasValue = false;
foreach (T x in source)
{
if (hasValue)
{
// if (x < value) // https://learn.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=netcore-3.1
// Less than zero This object precedes the object specified by the CompareTo method in the sort order.
// Zero This current instance occurs in the same position in the sort order as the object specified by the CompareTo method argument.
// Greater than zero
if (x.CompareTo(value) < 0)
value = x;
}
else
{
value = x;
hasValue = true;
}
}
if (hasValue)
return value;
throw new System.InvalidOperationException("Sequence contains no elements");
}
public static T Max<T>(params T[] source)
where T : struct, IComparable<T>
{
if (source == null)
throw new System.ArgumentNullException("source");
T value = default(T);
bool hasValue = false;
foreach (T x in source)
{
if (hasValue)
{
// if (x > value) // https://learn.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=netcore-3.1
// Less than zero This object precedes the object specified by the CompareTo method in the sort order.
// Zero This current instance occurs in the same position in the sort order as the object specified by the CompareTo method argument.
// Greater than zero
if (x.CompareTo(value) > 0)
value = x;
}
else
{
value = x;
hasValue = true;
}
}
if (hasValue)
return value;
throw new System.InvalidOperationException("Sequence contains no elements");
}
Related
In the internal source there is such a constructor public HashSetEqualityComparer(IEqualityComparer<T> comparer) but it's internal so I can't use it.
By default, HashSet<T>.CreateSetComparer() just uses the parameterless constructor which will apply EqualityComparer<T>.Default.
Is there a way to get a HashSetEqualityComparer<T> with a IEqualityComparer<T> of choice, without copying out the code from the source?
I think best solution is using SetEquals. It does the job you need and exactly in the same way that HashSetEqualityComparer does but it will account for any custom comparers defined in the sets its comparing.
So, in your specific scenario where you want to use a HashSet<T> as a key of a dictionary, you need to implement an IEqualityComparer<HashSet<T>> that makes use of SetEquals and "borrows" the reference source of HashSetEqualityComparer.GetHashCode():
public class CustomHashSetEqualityComparer<T>
: IEqualityComparer<HashSet<T>>
{
public bool Equals(HashSet<T> x, HashSet<T> y)
{
if (ReferenceEquals(x, null))
return false;
return x.SetEquals(y);
}
public int GetHashCode(HashSet<T> set)
{
int hashCode = 0;
if (set != null)
{
foreach (T t in set)
{
hashCode = hashCode ^
(set.Comparer.GetHashCode(t) & 0x7FFFFFFF);
}
}
return hashCode;
}
}
But yes, its a small pain that there is not way to directly create a SetEqualityComparer that leverages custom comparers but this unfortunate behavior is due, IMHO, more to a bug of the existing implementation than a lack of the needed overload; there is no reason why CreateSetComparer() can't return an IEqualityComparer that actually uses the comparers of the sets its comparing as the code above demonstrates.
If I had a voice in it, CreateSetComparer() wouldn't be static method at all. It would then be obvious, or at least predictable, that whatever comparer was returned would be created with the current set's comparer.
I agree #InBetween, using SetEquals is the best way. Even if add the constructor still can not achieve what you want.
please see this code:
http://referencesource.microsoft.com/#System.Core/System/Collections/Generic/HashSet.cs,1360
Here is I try to do:
class HashSetEqualityComparerWrapper<T> : IEqualityComparer<HashSet<T>>
{
static private Type HashSetEqualityComparerType = HashSet<T>.CreateSetComparer().GetType();
private IEqualityComparer<HashSet<T>> _comparer;
public HashSetEqualityComparerWrapper()
{
_comparer = HashSet<T>.CreateSetComparer();
}
public HashSetEqualityComparerWrapper(IEqualityComparer<T> comparer)
{
_comparer = HashSet<T>.CreateSetComparer();
if (comparer != null)
{
FieldInfo m_comparer_field = HashSetEqualityComparerType.GetField("m_comparer", BindingFlags.NonPublic | BindingFlags.Instance);
m_comparer_field.SetValue(_comparer, comparer);
}
}
public bool Equals(HashSet<T> x, HashSet<T> y)
{
return _comparer.Equals(x, y);
}
public int GetHashCode(HashSet<T> obj)
{
return _comparer.GetHashCode(obj);
}
}
UPDATE
I took 5 mins to implement another version form HashSetEqualityComparer<T> source code. And rewrite the bool Equals(HashSet<T> x, HashSet<T> y) method. It is not complex. All code just copy and paste from source, I just revise a bit.
class CustomHashSetEqualityComparer<T> : IEqualityComparer<HashSet<T>>
{
private IEqualityComparer<T> m_comparer;
public CustomHashSetEqualityComparer()
{
m_comparer = EqualityComparer<T>.Default;
}
public CustomHashSetEqualityComparer(IEqualityComparer<T> comparer)
{
if (comparer == null)
{
m_comparer = EqualityComparer<T>.Default;
}
else
{
m_comparer = comparer;
}
}
// using m_comparer to keep equals properties in tact; don't want to choose one of the comparers
public bool Equals(HashSet<T> x, HashSet<T> y)
{
// http://referencesource.microsoft.com/#System.Core/System/Collections/Generic/HashSet.cs,1360
// handle null cases first
if (x == null)
{
return (y == null);
}
else if (y == null)
{
// set1 != null
return false;
}
// all comparers are the same; this is faster
if (AreEqualityComparersEqual(x, y))
{
if (x.Count != y.Count)
{
return false;
}
}
// n^2 search because items are hashed according to their respective ECs
foreach (T set2Item in y)
{
bool found = false;
foreach (T set1Item in x)
{
if (m_comparer.Equals(set2Item, set1Item))
{
found = true;
break;
}
}
if (!found)
{
return false;
}
}
return true;
}
public int GetHashCode(HashSet<T> obj)
{
int hashCode = 0;
if (obj != null)
{
foreach (T t in obj)
{
hashCode = hashCode ^ (m_comparer.GetHashCode(t) & 0x7FFFFFFF);
}
} // else returns hashcode of 0 for null hashsets
return hashCode;
}
// Equals method for the comparer itself.
public override bool Equals(Object obj)
{
CustomHashSetEqualityComparer<T> comparer = obj as CustomHashSetEqualityComparer<T>;
if (comparer == null)
{
return false;
}
return (this.m_comparer == comparer.m_comparer);
}
public override int GetHashCode()
{
return m_comparer.GetHashCode();
}
static private bool AreEqualityComparersEqual(HashSet<T> set1, HashSet<T> set2)
{
return set1.Comparer.Equals(set2.Comparer);
}
}
Avoid this class if you use custom comparers. It uses its own equality comparer to perform GetHashCode, but when performing Equals(Set1, Set2) if Set1 and Set2 have the same equality comparer, the the HashSetEqualityComparer will use the comparer of the sets. HashsetEqualityComparer will only use its own comparer for equals if Set1 and Set2 have different comparers
It gets worse. It calls HashSet.HashSetEquals, which has a bug in it (See https://referencesource.microsoft.com/#system.core/System/Collections/Generic/HashSet.cs line 1489, which is missing a if (set1.Count != set2.Count) return false before performing the subset check.
The bug is illustrated by the following program:
class Program
{
private class MyEqualityComparer : EqualityComparer<int>
{
public override bool Equals(int x, int y)
{
return x == y;
}
public override int GetHashCode(int obj)
{
return obj.GetHashCode();
}
}
static void Main(string[] args)
{
var comparer = HashSet<int>.CreateSetComparer();
var set1 = new HashSet<int>(new MyEqualityComparer()) { 1 };
var set2 = new HashSet<int> { 1, 2 };
Console.WriteLine(comparer.Equals(set1, set2));
Console.WriteLine(comparer.Equals(set2, set1)); //True!
Console.ReadKey();
}
}
Regarding other answers to this question (I don't have the rep to comment):
Wilhelm Liao: His answer also contains the bug because it's copied from the reference source
InBetween: The solution is not symmetric. CustomHashSetEqualityComparer.Equals(A, B) does not always equals CustomHashSetEqualityComparer.Equals(B, A). I would be scared of that.
I think a robust implementation should throw an exception if it encounters a set which has a different comparer to its own. It could always use its own comparer and ignore the set comparer, but that would give strange and unintuitive behaviour.
Additional to the original solution, we can simplify GetHashCode with HashCode.Combine function:
public int GetHashCode(HashSet<T> set) {
int hashCode = 0;
foreach (var item in set) {
hashCode ^= HashCode.Combine(item);
}
return hashCode;
}
Assume that I have two classes, Foo and Bar.
public class Foo<TFirst, TSecond, TThird, T>
where TFirst : IReadOnlyList<T>
where TThird : IEnumerable<T>
{
}
public class Bar<TFirst, TSecond, TThird, T>
where TFirst : IReadOnlyList<T>
{
}
Now I want to compare their generic types. I'm using equality comparer to operate on array of types. like Intersect, Subtract etc.
I don't want to compare Foo and Bar but I want to compare their Generic parameters.
for example if both type parameters have same constraint, they should be considered equal. if they have no constrained they should be considered equal too.
In above example TFirst of Foo should be considered equal to TFirst of Bar. as well as TSecond because they have no constraint. TThrids are not equal because they don't have same constraint.
So now I have Foo and Bar types. I want to analyze their type arguments and compare them against each other.
var fooType = typeof(Foo<,,,>);
var barType = typeof(Bar<,,,>);
var fooArgs = fooType.GetGenericArguments();
var barArgs = barType.GetGenericArguments();
var commonArgs = fooArgs.Intersect(barArgs, new GenericArgumentEqualityComparer()).ToArray();
var unknownBarArgs = barArgs.Except(commonArgs, new GenericArgumentEqualityComparer()).ToArray();
Following Equality comparer always returns false, no matter I use IsAssignableFrom or ==. what is the right way to do this?
public class GenericArgumentEqualityComparer : IEqualityComparer<Type>
{
public bool Equals(Type x, Type y)
{
if (x == null || y == null) return false;
var xcons = x.GetGenericParameterConstraints();
var ycons = y.GetGenericParameterConstraints();
if(xcons.Length != ycons.Length) return false;
foreach (var cons in xcons)
{
if (ycons.All(cons2 => !cons.IsAssignableFrom(cons2)))
return false;
}
return true;
}
public int GetHashCode(Type obj)
{
// code runs on T4 for code generation. performance doesn't matter.
return 0;
}
}
the unexpected behavior comes from the
cons.IsAssignableFrom
you cannot try to assign open generic type from derived to base even if hierarchically possible
take this as an example
var ien = typeof(IEnumerable<string>);
var iread = typeof(IReadOnlyList<string>);
//isAssignable will be true
var isAssignable = ien.IsAssignableFrom(iread);
//here because IsAssignableFrom work from BaseType.IsAssignableFrom(DerviedType)
var isAssignableIEn = iread.IsAssignableFrom(ien);
and this One
var ien = typeof(IEnumerable<>);
var iread = typeof(IReadOnlyList<>);
var isAssignable = ien.IsAssignableFrom(iread);
//here because IsAssignableFrom work from BaseType.IsAssignableFrom(DerviedType)
var isAssignableIEn = iread.IsAssignableFrom(ien);
both of the assignment checks will be false this is an expected behavior because an open generic type cannot be instantiated by default so is not assignable
to create an instance of open generic type you should use Type.MakeGenericType
To resolve your issue this may help you
public class GenericArgumentEqualityComparer : IEqualityComparer<Type>
{
public bool Equals(Type x, Type y)
{
var xInterfacesTypes = x.GetInterfaces();
var yInterfacesTypes = y.GetInterfaces();
if (!xInterfacesTypes.Any()&&!yInterfacesTypes.Any() )
{
return true;
}
if ((!xInterfacesTypes.Any() && yInterfacesTypes.Any()) || xInterfacesTypes.Any() && !yInterfacesTypes.Any())
{
return false;
}
foreach (var xInterfacesType in xInterfacesTypes)
{
var iType = xInterfacesType.IsGenericType ? xInterfacesType.GetGenericTypeDefinition() :xInterfacesType;
var yType = yInterfacesTypes.Any(yI => yI.IsGenericType && yI.GetGenericTypeDefinition() == iType||yI.GetType()==xInterfacesType.GetType());
if (!yType)
{
return false;
}
}
return true;
}
public int GetHashCode(Type obj)
{
return obj.Name.GetHashCode();
}
}
I have a MongoDB database where I store all pictures and when I retrieve them I have stored some doubles, which ain't so good, but anyway I want to show only distinct elements.
#foreach (Foto f in fotos.Distinct(new IEqualityComparer<Foto> { )
But the Foto class has one property called smallurl and I want to show only distinct elements by this property. So how to write a custom IEqualityComparer.
var listOfUrls = fotos.Select(f => f.smallurl).Distinct();
EDIT to specifically answer your question
Practically copied from the MSDN documentation that you can find with a search for c# IEqualityComparer http://msdn.microsoft.com/en-us/library/ms132151.aspx
class FotoEqualityComparer : IEqualityComparer<Foto>
{
public bool Equals(Foto f1, Foto f2)
{
return f1.smallurl == f2.smallurl;
}
public int GetHashCode(Foto f)
{
return f.smallurl.GetHashCode();
}
}
#foreach (Foto f in fotos.Distinct(new FotoEqualityComparer() )
It's actually pretty easy. Simply provide a distinct-ness selector for your method like so:
public static IEnumerable<TSource> DistinctBy<TSource, TResult>(this IEnumerable<TSource> enumerable, Func<TSource, TResult> keySelector)
{
Dictionary<TResult, TSource> seenItems = new Dictionary<TResult, TSource>();
foreach (var item in enumerable)
{
var key = keySelector(item);
if (!seenItems.ContainsKey(key))
{
seenItems.Add(key, item);
yield return item;
}
}
}
Alternatively, you can create another one to make a generic implementation fo the IEquality comparer:
public static IEnumerable<TSource> DistinctBy<TSource>(this IEnumerable<TSource> enumerable, Func<TSource, TSource, bool> equalitySelector, Func<TSource, int> hashCodeSelector)
{
return enumerable.Distinct(new GenericEqualitySelector<TSource>(equalitySelector, hashCodeSelector));
}
class GenericEqualitySelector<TSource> : IEqualityComparer<TSource>
{
public Func<TSource, TSource, bool> _equalityComparer = null;
public Func<TSource, int> _hashSelector = null;
public GenericEqualitySelector(Func<TSource, TSource, bool> selector, Func<TSource, int> hashSelector)
{
_equalityComparer = selector;
_hashSelector = hashSelector;
}
public bool Equals(TSource x, TSource y)
{
return _equalityComparer(x, y);
}
public int GetHashCode(TSource obj)
{
return _hashSelector(obj);
}
}
Create your own:
public class FotoEqualityComparer : IEqualityComparer<Foto>
{
public bool Equals(Foto x, Foto y)
{
return x.smallurl.Equals(y.smallurl);
}
public int GetHashCode(Foto foto)
{
return foto.smallurl.GetHashCode();
}
}
And use it like so:
fotos.Distinct(new FotoEqualityComparer());
EDIT:
There's no inline lambda overload of .Distinct() because when two objects compare equal they must have the same GetHashCode return value (or else the hash table used internally by Distinct will not function correctly).
But if you want it in one line, then you could also do grouping to achieve the same result:
fotos.GroupBy(f => f.smallurl).Select(g => g.First());
Modified from MSDN
public class MyEqualityComparer : IEqualityComparer<Foto>
{
public bool Equals(Foto x, Foto 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 foto's properties are equal.
return x.smallurl == y.smallurl ;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(Foto foto)
{
//Check whether the object is null
if (Object.ReferenceEquals(foto, null)) return 0;
//Get hash code for the foto.smallurl field if it is not null.
return foto.smallurl == null ? 0 : foto.smallurl.GetHashCode();
}
}
Much simpler code using GroupBy instead:
#foreach (Foto f in fotos.GroupBy(f => f.smallurl).Select(g => g.First()))
You should create your own EqulityComparer:
class FotoEqualityComparer : IEqualityComparer<Foto>
{
public bool Equals(Foto b1, Foto b2)
{
if (b1.smallurl == b2.smallurl)
return true;
else
return false;
}
public int GetHashCode(Foto bx)
{
int hCode = bx.smallurl ;
return hCode.GetHashCode();
}
}
I have a List of objects in C#. All of the objects contain the properties dept and course.
There are several objects that have the same dept and course.
How can I trim the List(or make a new List) where there is only one object per unique (dept & course) properties.
[Any additional duplicates are dropped out of the List]
I know how to do this with a single property:
fooList.GroupBy(x => x.dept).Select(x => x.First());
However, I am wondering how to do this for multiple properties (2 or more)?
To use multiple properties you can use an anonymous type:
var query = fooList.GroupBy(x => new { x.Dept, x.Course })
.Select(x => x.First());
Of course, this depends on what types Dept and Course are to determine equality. Alternately, your classes can implement IEqualityComparer<T> and then you could use the Enumerable.Distinct method that accepts a comparer.
Another approach is to use the LINQ Distinct extension method together with an IEqualityComparer<Foo>. It requires you to implement a comparer; however, the latter is reusable and testable.
public class FooDeptCourseEqualityComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
return
x.Dept == y.Dept &&
x.Course.ToLower() == y.Course.ToLower();
}
public int GetHashCode(Foo obj)
{
unchecked {
return 527 + obj.Dept.GetHashCode() * 31 + obj.Course.GetHashCode();
}
}
#region Singleton Pattern
public static readonly FooDeptCourseEqualityComparer Instance =
new FooDeptCourseEqualityComparer();
private FooDeptCourseEqualityComparer() { }
#endregion
}
My example uses the singleton pattern. Since the class does not have any state information, we do not need to create a new instance each time we use it.
My code does not handle null values. Of course you would have to handle them, if they can occur.
The unique values are returned like this
var result = fooList.Distinct(FooDeptCourseEqualityComparer.Instance);
UPDATE
I suggest using a generic EqualityComparer class that accepts lambda expressions in the constructor and can be reused in multiple situations
public class LambdaEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, T, bool> _areEqual;
private Func<T, int> _getHashCode;
public LambdaEqualityComparer(Func<T, T, bool> areEqual,
Func<T, int> getHashCode)
{
_areEqual = areEqual;
_getHashCode = getHashCode;
}
public LambdaEqualityComparer(Func<T, T, bool> areEqual)
: this(areEqual, obj => obj.GetHashCode())
{
}
#region IEqualityComparer<T> Members
public bool Equals(T x, T y)
{
return _areEqual(x, y);
}
public int GetHashCode(T obj)
{
return _getHashCode(obj);
}
#endregion
}
You can use it like this
var comparer = new LambdaEqualityComparer<Foo>(
(x, y) => x.Dept == y.Dept && x.Course == y.Course,
obj => {
unchecked {
return 527 + obj.Dept.GetHashCode() * 31 + obj.Course.GetHashCode();
}
}
);
var result = fooList.Distinct(comparer);
Note: You have to provide a calculation of the hash code, since Distinct uses an internal Set<T> class, which in turn uses hash codes.
UPDATE #2
An even more generic equality comparer implements the comparison automatically and accepts a list of property accessors; however, you have no control, on how the comparison is performed.
public class AutoEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, object>[] _propertyAccessors;
public AutoEqualityComparer(params Func<T, object>[] propertyAccessors)
{
_propertyAccessors = propertyAccessors;
}
#region IEqualityComparer<T> Members
public bool Equals(T x, T y)
{
foreach (var getProp in _propertyAccessors) {
if (!getProp(x).Equals(getProp(y))) {
return false;
}
}
return true;
}
public int GetHashCode(T obj)
{
unchecked {
int hash = 17;
foreach (var getProp in _propertyAccessors) {
hash = hash * 31 + getProp(obj).GetHashCode();
}
return hash;
}
}
#endregion
}
Usage
var comparer = new AutoEqualityComparer<Foo>(foo => foo.Dept,
foo => foo.Course);
var result = fooList.Distinct(comparer);
Currently I'm using
var x = dict.ContainsKey(key) ? dict[key] : defaultValue
I'd like some way to have dictionary[key] return null for nonexistant keys, so I could write something like
var x = dict[key] ?? defaultValue;
this also winds up being part of linq queries etc. so I'd prefer one-line solutions.
With an extension method:
public static class MyHelper
{
public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dic,
K key,
V defaultVal = default(V))
{
V ret;
bool found = dic.TryGetValue(key, out ret);
if (found) { return ret; }
return defaultVal;
}
void Example()
{
var dict = new Dictionary<int, string>();
dict.GetValueOrDefault(42, "default");
}
}
You can use a helper method:
public abstract class MyHelper {
public static V GetValueOrDefault<K,V>( Dictionary<K,V> dic, K key ) {
V ret;
bool found = dic.TryGetValue( key, out ret );
if ( found ) { return ret; }
return default(V);
}
}
var x = MyHelper.GetValueOrDefault( dic, key );
Here is the "ultimate" solution, in that it is implemented as an extension method, uses the IDictionary interface, provides an optional default value, and is written concisely.
public static TV GetValueOrDefault<TK, TV>(this IDictionary<TK, TV> dic, TK key,
TV defaultVal=default(TV))
{
TV val;
return dic.TryGetValue(key, out val)
? val
: defaultVal;
}
Isn't simply TryGetValue(key, out value) what you are looking for? Quoting MSDN:
When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized.
from http://msdn.microsoft.com/en-us/library/bb347013(v=vs.90).aspx