如何评估LINQ中两个异构集之间的集差?



在(更多)LINQ术语中,我如何通过涉及不同类型来执行except ?

例如,给定下面定义的LeverPosting结构,IEnumerable<LeverPosting>IEnumerable<string>,我如何找到所有"不在"的LeverPostings?alreadyProcessedIds名单?

class LeverPosting
{
public string Id {get; set;}
}

通常你会这样做:

IEnumerable<LeverPosting> postings = ...
IEnumerable<string> idsalreadyProcessedIds = ...
var idsalreadyProcessedIds2 = new HashSet<string>(idsalreadyProcessedIds);
var postings2 = postings.Where(x => !idsalreadyProcessedIds2.Contains(x.Id)));

这是我想出的一个扩展方法:

public static class LinqExtensions
{
/// <summary>
/// Similar to MoreLinq's ExceptBy method but works on heterogeneous types.
/// </summary>
public static IEnumerable<TSource> ExceptBy<TSource, TOther, TKey>(this IEnumerable<TSource> sourceItems,
IEnumerable<TOther> otherItems, Func<TSource, TKey> sourceKeyFunc, Func<TOther, TKey> otherKeyFunc)
{
return from sourceItem in sourceItems
join otherItem in otherItems on sourceKeyFunc.Invoke(sourceItem) equals otherKeyFunc.Invoke(otherItem)
into gj
from subSourceItem in gj.DefaultIfEmpty()        // left outer join
subSourceItem.Equals(default(TOther))            // only items on the left that don't match the set on the right
select sourceItem;
}
}

或基于@xanatos答案的另一个扩展方法:

/// <summary>
/// Similar to MoreLinq's ExceptBy method but works on heterogeneous types.
/// </summary>
public static IEnumerable<TSource> ExceptBy2<TSource, TOther, TKey>(this IEnumerable<TSource> sourceItems,
IEnumerable<TOther> otherItems, Func<TSource, TKey> sourceKeyFunc, Func<TOther, TKey> otherKeyFunc)
{
var otherItemKeyHashset = otherItems
.Select(si => otherKeyFunc.Invoke(si))
.ToHashSet();
return sourceItems
.Where(oi => !otherItemKeyHashset.Contains(sourceKeyFunc.Invoke(oi)));
}

用法:

public static IEnumerable<LeverPosting> ExceptAlreadyProcessed(this IEnumerable<LeverPosting> postings, IEnumerable<string> alreadyProcessedIds) =>
postings.ExceptBy(
alreadyProcessedIds, 
posting => posting.Id,
alreadyProcessedId => alreadyProcessedId
);

请告诉我是否有像MoreLinq这样的lib已经这样做了。