Cod*_*rer 57 .net c# linq lambda
因此,.NET 3.0/3.5为我们提供了许多查询,排序和操作数据的新方法,这要归功于LINQ提供的所有简洁功能.有时,我需要比较没有内置比较运算符的用户定义类型.在许多情况下,比较非常简单 - 比如foo1.key?= foo2.key.我可以使用匿名委托/ lambda函数简单地指定内联比较,而不是为该类型创建新的IEqualityComparer吗?就像是:
var f1 = ...,
f2 = ...;
var f3 = f1.Except(
f2, new IEqualityComparer(
(Foo a, Foo b) => a.key.CompareTo(b.key)
) );
Run Code Online (Sandbox Code Playgroud)
我很确定上面的内容实际上并不奏效.我只是不想让整个班级做一些"沉重"的事情只是为了告诉程序如何比较苹果和苹果.
Jon*_*eet 66
我的MiscUtil库包含一个ProjectionComparer,用于从投影委托构建IComparer <T>.让ProjectionEqualityComparer做同样的事情将是10分钟的工作.
编辑:这是ProjectionEqualityComparer的代码:
using System;
using System.Collections.Generic;
/// <summary>
/// Non-generic class to produce instances of the generic class,
/// optionally using type inference.
/// </summary>
public static class ProjectionEqualityComparer
{
/// <summary>
/// Creates an instance of ProjectionEqualityComparer using the specified projection.
/// </summary>
/// <typeparam name="TSource">Type parameter for the elements to be compared</typeparam>
/// <typeparam name="TKey">Type parameter for the keys to be compared,
/// after being projected from the elements</typeparam>
/// <param name="projection">Projection to use when determining the key of an element</param>
/// <returns>A comparer which will compare elements by projecting
/// each element to its key, and comparing keys</returns>
public static ProjectionEqualityComparer<TSource, TKey> Create<TSource, TKey>(Func<TSource, TKey> projection)
{
return new ProjectionEqualityComparer<TSource, TKey>(projection);
}
/// <summary>
/// Creates an instance of ProjectionEqualityComparer using the specified projection.
/// The ignored parameter is solely present to aid type inference.
/// </summary>
/// <typeparam name="TSource">Type parameter for the elements to be compared</typeparam>
/// <typeparam name="TKey">Type parameter for the keys to be compared,
/// after being projected from the elements</typeparam>
/// <param name="ignored">Value is ignored - type may be used by type inference</param>
/// <param name="projection">Projection to use when determining the key of an element</param>
/// <returns>A comparer which will compare elements by projecting
/// each element to its key, and comparing keys</returns>
public static ProjectionEqualityComparer<TSource, TKey> Create<TSource, TKey>
(TSource ignored,
Func<TSource, TKey> projection)
{
return new ProjectionEqualityComparer<TSource, TKey>(projection);
}
}
/// <summary>
/// Class generic in the source only to produce instances of the
/// doubly generic class, optionally using type inference.
/// </summary>
public static class ProjectionEqualityComparer<TSource>
{
/// <summary>
/// Creates an instance of ProjectionEqualityComparer using the specified projection.
/// </summary>
/// <typeparam name="TKey">Type parameter for the keys to be compared,
/// after being projected from the elements</typeparam>
/// <param name="projection">Projection to use when determining the key of an element</param>
/// <returns>A comparer which will compare elements by projecting each element to its key,
/// and comparing keys</returns>
public static ProjectionEqualityComparer<TSource, TKey> Create<TKey>(Func<TSource, TKey> projection)
{
return new ProjectionEqualityComparer<TSource, TKey>(projection);
}
}
/// <summary>
/// Comparer which projects each element of the comparison to a key, and then compares
/// those keys using the specified (or default) comparer for the key type.
/// </summary>
/// <typeparam name="TSource">Type of elements which this comparer
/// will be asked to compare</typeparam>
/// <typeparam name="TKey">Type of the key projected
/// from the element</typeparam>
public class ProjectionEqualityComparer<TSource, TKey> : IEqualityComparer<TSource>
{
readonly Func<TSource, TKey> projection;
readonly IEqualityComparer<TKey> comparer;
/// <summary>
/// Creates a new instance using the specified projection, which must not be null.
/// The default comparer for the projected type is used.
/// </summary>
/// <param name="projection">Projection to use during comparisons</param>
public ProjectionEqualityComparer(Func<TSource, TKey> projection)
: this(projection, null)
{
}
/// <summary>
/// Creates a new instance using the specified projection, which must not be null.
/// </summary>
/// <param name="projection">Projection to use during comparisons</param>
/// <param name="comparer">The comparer to use on the keys. May be null, in
/// which case the default comparer will be used.</param>
public ProjectionEqualityComparer(Func<TSource, TKey> projection, IEqualityComparer<TKey> comparer)
{
if (projection == null)
{
throw new ArgumentNullException("projection");
}
this.comparer = comparer ?? EqualityComparer<TKey>.Default;
this.projection = projection;
}
/// <summary>
/// Compares the two specified values for equality by applying the projection
/// to each value and then using the equality comparer on the resulting keys. Null
/// references are never passed to the projection.
/// </summary>
public bool Equals(TSource x, TSource y)
{
if (x == null && y == null)
{
return true;
}
if (x == null || y == null)
{
return false;
}
return comparer.Equals(projection(x), projection(y));
}
/// <summary>
/// Produces a hash code for the given value by projecting it and
/// then asking the equality comparer to find the hash code of
/// the resulting key.
/// </summary>
public int GetHashCode(TSource obj)
{
if (obj == null)
{
throw new ArgumentNullException("obj");
}
return comparer.GetHashCode(projection(obj));
}
}
Run Code Online (Sandbox Code Playgroud)
以下是一个示例用法:
var f3 = f1.Except(f2, ProjectionEqualityComparer<Foo>.Create(a => a.key));
Run Code Online (Sandbox Code Playgroud)
mik*_*ike 20
这是一个简单的助手类,应该做你想要的
public class EqualityComparer<T> : IEqualityComparer<T>
{
public EqualityComparer(Func<T, T, bool> cmp)
{
this.cmp = cmp;
}
public bool Equals(T x, T y)
{
return cmp(x, y);
}
public int GetHashCode(T obj)
{
return obj.GetHashCode();
}
public Func<T, T, bool> cmp { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
你可以像这样使用它:
processed.Union(suburbs, new EqualityComparer<Suburb>((s1, s2)
=> s1.SuburbId == s2.SuburbId));
Run Code Online (Sandbox Code Playgroud)
我发现在IEnumerable上提供额外的帮助是一种更干净的方法.
见:这个问题
所以你可以:
var f3 = f1.Except(
f2,
(a, b) => a.key.CompareTo(b.key)
);
Run Code Online (Sandbox Code Playgroud)
如果正确定义扩展方法
为什么不是这样的:
public class Comparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> _equalityComparer;
public Comparer(Func<T, T, bool> equalityComparer)
{
_equalityComparer = equalityComparer;
}
public bool Equals(T first, T second)
{
return _equalityComparer(first, second);
}
public int GetHashCode(T value)
{
return value.GetHashCode();
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以例如像(如在的情况下做Intersect的IEnumerable<T>):
list.Intersect(otherList, new Comparer<T>( (x, y) => x.Property == y.Property));
Run Code Online (Sandbox Code Playgroud)
本Comparer类可以放在一个公共事业项目,被需要的地方使用.
我现在才看到Sam Saffron的答案(与此非常相似).
所以我知道这是您的问题的解决方法,但是当我发现我遇到了您在此处遇到的情况(组合列表并过滤重复项)并且 Distinct 需要一个我没有的 IEquityComparer 时,我通常会去使用 Concat -> 组 -> 选择。
原来的
var f1 = ...,
f2 = ...;
var f3 = f1.Except(
f2, new IEqualityComparer(
(Foo a, Foo b) => a.key.CompareTo(b.key)
) );
Run Code Online (Sandbox Code Playgroud)
新的
var f1 = ...,
f2 = ...;
var distinctF = f1
.Concat(f2) // Combine the lists
.GroupBy(x => x.key) // Group them up by our equity comparison key
.Select(x => x.FirstOrDefault()); // Just grab one of them.
Run Code Online (Sandbox Code Playgroud)
请注意,在 GroupBy() 中,您有机会添加逻辑来创建混合键,例如:
.GroupBy(f => new Uri(f.Url).PathAndQuery)
Run Code Online (Sandbox Code Playgroud)
以及在 Select() 中,如果您想指定结果项目来自哪个列表,您可以说:
.Select(x => x.FirstOrDefault(y => f1.Contains(y))
Run Code Online (Sandbox Code Playgroud)
希望有帮助!
| 归档时间: |
|
| 查看次数: |
41995 次 |
| 最近记录: |