をこの:
var newData = destination.Except(data.Select(x => f(x)));
あなたは "に含まれている同じタイプの「データ」を投影する必要があり先」が、あなたの下のコードを使用したが、この制限を取り除くことができます:
//Here is how you can compare two different sets.
class A { public string Bar { get; set; } }
class B { public string Foo { get; set; } }
IEnumerable<A> setOfA = new A[] { /*...*/ };
IEnumerable<B> setOfB = new B[] { /*...*/ };
var subSetOfA1 = setOfA.Except(setOfB, a => a.Bar, b => b.Foo);
//alternatively you can do it with a custom EqualityComparer, if your not case sensitive for instance.
var subSetOfA2 = setOfA.Except(setOfB, a => a.Bar, b => b.Foo, StringComparer.OrdinalIgnoreCase);
//Here is the extension class definition allowing you to use the code above
public static class IEnumerableExtension
{
public static IEnumerable<TFirst> Except<TFirst, TSecond, TCompared>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TCompared> firstSelect,
Func<TSecond, TCompared> secondSelect)
{
return Except(first, second, firstSelect, secondSelect, EqualityComparer<TCompared>.Default);
}
public static IEnumerable<TFirst> Except<TFirst, TSecond, TCompared>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TCompared> firstSelect,
Func<TSecond, TCompared> secondSelect,
IEqualityComparer<TCompared> comparer)
{
if (first == null)
throw new ArgumentNullException("first");
if (second == null)
throw new ArgumentNullException("second");
return ExceptIterator<TFirst, TSecond, TCompared>(first, second, firstSelect, secondSelect, comparer);
}
private static IEnumerable<TFirst> ExceptIterator<TFirst, TSecond, TCompared>(
IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TCompared> firstSelect,
Func<TSecond, TCompared> secondSelect,
IEqualityComparer<TCompared> comparer)
{
HashSet<TCompared> set = new HashSet<TCompared>(second.Select(secondSelect), comparer);
foreach (TFirst tSource1 in first)
if (set.Add(firstSelect(tSource1)))
yield return tSource1;
}
}
一部は、それが原因のHashSetの使用メモリは非効率的だと主張します。しかし、実際には、フレームワークのEnumerable.Exceptメソッドは、同様の内部クラス 'Set'(私は逆コンパイルで見た)と同じことをやっています。
貧弱な古い 'for'ループは、かつてはとても有用でしたが、残念なことに、彼は一人の人間を幸せにすることはありません。 – Marc
@Marc:あなたが表現している感情には同意しません。私たちはコードを書く方法を持っていますが、そのメカニズムについて心配することなく、意図をより明確に表現することができます。 'のために'はメカニズムを表現し、意図を隠す。あなたがしばしば拒否しているLINQベースの1ライナーは、(いつもとは限りませんが)意図をよりよく表現し、メカニズムを隠すことができます。これにより、理解しやすく保守しやすいコードになります。 – jason
@ジェイソン、私は軽度であったが、あなたのような投射に投げる機能は、意図の仮定を提供するだけである。 – Marc