code_junkie

Wrap a delegate in an IEqualityComparer

Nov 11th, 2011
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.44 KB | None | 0 0
  1. class Comparer<T>: IEqualityComparer<T>
  2. {
  3. private readonly Func<T, T, bool> _comparer;
  4.  
  5. public Comparer(Func<T, T, bool> comparer)
  6. {
  7. if (comparer == null)
  8. throw new ArgumentNullException("comparer");
  9.  
  10. _comparer = comparer;
  11. }
  12.  
  13. public bool Equals(T x, T y)
  14. {
  15. return _comparer(x, y);
  16. }
  17.  
  18. public int GetHashCode(T obj)
  19. {
  20. return obj.ToString().ToLower().GetHashCode();
  21. }
  22. }
  23.  
  24. ...
  25.  
  26. Func<int, int, bool> f = (x, y) => x == y;
  27. var comparer = new Comparer<int>(f);
  28. Console.WriteLine(comparer.Equals(1, 1));
  29. Console.WriteLine(comparer.Equals(1, 2));
  30.  
  31. var foo = new List<string> { "abc", "de", "DE" };
  32.  
  33. // case-insensitive distinct
  34. var distinct = foo.Distinct(new KeyEqualityComparer<string>( x => x.ToLower() ) );
  35.  
  36. public class KeyEqualityComparer<T> : IEqualityComparer<T>
  37. {
  38. private readonly Func<T, object> keyExtractor;
  39.  
  40. public KeyEqualityComparer(Func<T,object> keyExtractor)
  41. {
  42. this.keyExtractor = keyExtractor;
  43. }
  44.  
  45. public bool Equals(T x, T y)
  46. {
  47. return this.keyExtractor(x).Equals(this.keyExtractor(y));
  48. }
  49.  
  50. public int GetHashCode(T obj)
  51. {
  52. return this.keyExtractor(obj).GetHashCode();
  53. }
  54. }
  55.  
  56. class Value
  57. {
  58. public string Name { get; private set; }
  59. public int Number { get; private set; }
  60.  
  61. public Value(string name, int number)
  62. {
  63. Name = name;
  64. Number = number;
  65. }
  66.  
  67. public override string ToString()
  68. {
  69. return string.Format("{0}: {1}", Name, Number);
  70. }
  71. }
  72.  
  73. var comparer = new Comparer<Value>((x, y) => x.Name == y.Name);
  74.  
  75. var values = new List<Value>();
  76.  
  77. var random = new Random();
  78. for (int i = 0; i < 10; ++i)
  79. {
  80. values.Add("x", random.Next());
  81. }
  82.  
  83. var distinct = values.Distinct(comparer);
  84.  
  85. foreach (Value x in distinct)
  86. {
  87. Console.WriteLine(x);
  88. }
  89.  
  90. GroupBy
  91.  
  92. var grouped = values.GroupBy(x => x, comparer);
  93.  
  94. foreach (IGrouping<Value> g in grouped)
  95. {
  96. Console.WriteLine("[KEY: '{0}']", g);
  97. foreach (Value x in g)
  98. {
  99. Console.WriteLine(x);
  100. }
  101. }
  102.  
  103. Distinct
  104.  
  105. var uniqueValues = new HashSet<Value>(values, comparer);
  106.  
  107. foreach (Value x in uniqueValues)
  108. {
  109. Console.WriteLine(x);
  110. }
  111.  
  112. GetHashCode
  113.  
  114. public class KeyEqualityComparer<T, TKey> : IEqualityComparer<T>
  115. {
  116. protected readonly Func<T, TKey> keyExtractor;
  117.  
  118. public KeyEqualityComparer(Func<T, TKey> keyExtractor)
  119. {
  120. this.keyExtractor = keyExtractor;
  121. }
  122.  
  123. public virtual bool Equals(T x, T y)
  124. {
  125. return this.keyExtractor(x).Equals(this.keyExtractor(y));
  126. }
  127.  
  128. public int GetHashCode(T obj)
  129. {
  130. return this.keyExtractor(obj).GetHashCode();
  131. }
  132. }
  133.  
  134. public class StrictKeyEqualityComparer<T, TKey> : KeyEqualityComparer<T, TKey>
  135. where TKey : IEquatable<TKey>
  136. {
  137. public StrictKeyEqualityComparer(Func<T, TKey> keyExtractor)
  138. : base(keyExtractor)
  139. { }
  140.  
  141. public override bool Equals(T x, T y)
  142. {
  143. // This will use the overload that accepts a TKey parameter
  144. // instead of an object parameter.
  145. return this.keyExtractor(x).Equals(this.keyExtractor(y));
  146. }
  147. }
  148.  
  149. public class FuncEqualityComparer<T> : IEqualityComparer<T>
  150. {
  151. readonly Func<T, T, bool> _comparer;
  152. readonly Func<T, int> _hash;
  153.  
  154. public FuncEqualityComparer( Func<T, T, bool> comparer )
  155. : this( comparer, t => t.GetHashCode())
  156. {
  157. }
  158.  
  159. public FuncEqualityComparer( Func<T, T, bool> comparer, Func<T, int> hash )
  160. {
  161. _comparer = comparer;
  162. _hash = hash;
  163. }
  164.  
  165. public bool Equals( T x, T y )
  166. {
  167. return _comparer( x, y );
  168. }
  169.  
  170. public int GetHashCode( T obj )
  171. {
  172. return _hash( obj );
  173. }
  174. }
  175.  
  176. public static class SequenceExtensions
  177. {
  178. public static bool SequenceEqual<T>( this IEnumerable<T> first, IEnumerable<T> second, Func<T, T, bool> comparer )
  179. {
  180. return first.SequenceEqual( second, new FuncEqualityComparer<T>( comparer ) );
  181. }
  182.  
  183. public static bool SequenceEqual<T>( this IEnumerable<T> first, IEnumerable<T> second, Func<T, T, bool> comparer, Func<T, int> hash )
  184. {
  185. return first.SequenceEqual( second, new FuncEqualityComparer<T>( comparer, hash ) );
  186. }
  187. }
  188.  
  189. class FuncEqualityComparer<T> : IEqualityComparer<T>
  190. {
  191. readonly Func<T, T, bool> _comparer;
  192. readonly Func<T, int> _hash;
  193.  
  194. public FuncEqualityComparer( Func<T, T, bool> comparer )
  195. : this( comparer, t => 0 ) // NB Cannot assume anything about how e.g., t.GetHashCode() interacts with the comparer's behavior
  196. {
  197. }
  198.  
  199. public FuncEqualityComparer( Func<T, T, bool> comparer, Func<T, int> hash )
  200. {
  201. _comparer = comparer;
  202. _hash = hash;
  203. }
  204.  
  205. public bool Equals( T x, T y )
  206. {
  207. return _comparer( x, y );
  208. }
  209.  
  210. public int GetHashCode( T obj )
  211. {
  212. return _hash( obj );
  213. }
  214. }
  215.  
  216. public static IEnumerable<T> Distinct<T>(this IEnumerable<T> list, Func<T, object> keyExtractor)
  217. {
  218. return list.Distinct(new KeyEqualityComparer<T>(keyExtractor));
  219. }
  220. var distinct = foo.Distinct(x => x.ToLower())
  221.  
  222. public class MyComparer<T> : IEqualityComparer<T>
  223. {
  224. public bool Equals(T x, T y)
  225. {
  226. return EqualityComparer<T>.Default.Equals(x, y);
  227. }
  228.  
  229. public int GetHashCode(T obj)
  230. {
  231. return obj.GetHashCode();
  232. }
  233. }
  234.  
  235. public static Dictionary<TKey, TValue> Distinct<TKey, TValue>(this IEnumerable<TValue> items, Func<TValue, TKey> selector)
  236. {
  237. Dictionary<TKey, TValue> result = null;
  238. ICollection collection = items as ICollection;
  239. if (collection != null)
  240. result = new Dictionary<TKey, TValue>(collection.Count);
  241. else
  242. result = new Dictionary<TKey, TValue>();
  243. foreach (TValue item in items)
  244. result[selector(item)] = item;
  245. return result;
  246. }
  247.  
  248. public static class Equality<T>
  249. {
  250. public static IEqualityComparer<T> CreateComparer<V>(Func<T, V> keySelector)
  251. {
  252. return new KeyEqualityComparer<V>(keySelector);
  253. }
  254. public static IEqualityComparer<T> CreateComparer<V>(Func<T, V> keySelector, IEqualityCo
  255. {
  256. return new KeyEqualityComparer<V>(keySelector, comparer);
  257. }
  258. class KeyEqualityComparer<V> : IEqualityComparer<T>
  259. {
  260. private Func<T, V> keySelector;
  261. private IEqualityComparer<V> comparer;
  262.  
  263. public KeyEqualityComparer(Func<T, V> keySelector, IEqualityComparer<V> comparer)
  264. {
  265. this.keySelector = keySelector;
  266. this.comparer = comparer;
  267. }
  268. public KeyEqualityComparer(Func<T, V> keySelector)
  269. : this(keySelector, EqualityComparer<V>.Default)
  270. { }
  271. public bool Equals(T x, T y)
  272. {
  273. return comparer.Equals(keySelector(x), keySelector(y));
  274. }
  275. public int GetHashCode(T obj)
  276. {
  277. return comparer.GetHashCode(keySelector(obj));
  278. }
  279. }
  280. }
  281.  
  282. var comparer1 = Equality<Person>.CreateComparer(p => p.ID);
  283. var comparer2 = Equality<Person>.CreateComparer(p => p.Name);
  284. var comparer3 = Equality<Person>.CreateComparer(p => p.Birthday.Year);
  285. var comparer4 = Equality<Person>.CreateComparer(p => p.Name, StringComparer.CurrentCultureIgnoreCase);
  286.  
  287. class Person
  288. {
  289. public int ID { get; set; }
  290. public string Name { get; set; }
  291. public DateTime Birthday { get; set; }
  292. }
  293.  
  294. public class MyComparer<T> : IEqualityComparer<T>
  295. {
  296. private Func<T, T, bool> _compare;
  297. MyComparer(Func<T, T, bool> compare)
  298. {
  299. _compare = compare;
  300. }
  301.  
  302. public bool Equals(T x, Ty)
  303. {
  304. return _compare(x, y);
  305. }
  306.  
  307. public int GetHashCode(T obj)
  308. {
  309. return obj.GetHashCode();
  310. }
  311. }
Add Comment
Please, Sign In to add comment