LINQ 惰性内连接

LINQ Lazy Inner Join

有没有办法利用 LINQ API 以惰性方式(内部)加入集合?我面临这样一种情况,我需要在级联中关联多个 CSV,并且如果“上游”CSV 结果为空,我想避免不必要的解析操作:

ReadCsvRows(fileA).Join(
    ReadCsvRows(fileB), // why to parse B if A is empty?!
    ...
).Join(
    ReadCsvRows(fileC),
    ...
).Join(...)

请注意,ReadCsvRows 方法位于接口之后,唯一的要求是该方法必须 return IEnumerable(如 here 所示)。为了让事情“流畅”,我可以通过引入自定义扩展方法来解决这个问题

public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
    this IEnumerable<TOuter> outer, 
    Func<IEnumerable<TInner>> innerFunc, 
    Func<TOuter, TKey> outerKeySelector, 
    Func<TInner, TKey> innerKeySelector, 
    Func<TOuter, TInner, TResult> resultSelector) =>
        !outer.Any() ?
        Array.Empty<TResult>() :
        outer.Join(
            innerFunc(),
            outerKeySelector,
            innerKeySelector,
            resultSelector
        );

但想知道我对 vanilla LINQ 有哪些选择 API。

如果我是你,我会将 ReadCsvRows(fileB) 和 ReadCsvRows(fileC) 分成两个单独的变量。并添加一个“If”条件来确定是否应该执行“ReadCSVRows(fileB)”。

像这样:

List<FileATypeA> fileAData = ReadCsvRows(fileA);
List<FileATypeB> fileBData = new List<FileATypeB>();
List<FileATypeC> fileCData =  new List<FileTypeC>();

if(fileAData.Count() > 0)
    fileBData = ReadCsvRows(fileB);
if(fileBData.Count() > 0)
    fileCData = ReadCsvRows(fileC);

List<FinalType> final = from a in fileAData
                        join b in fileBData
                             on a.Key = b.Key
                        join c in fileCData
                             on b.Key = c.Key

看看这是否有帮助

您不需要自己的 Join 实现。如果 outer 没有记录,标准 System.Linq 实现不会枚举 inner 序列。

因此,请检查您的 ReadCsvRows 实施。如果您在它的主体中使用 yield return,则不会出现不需要的读取。

示意图:

public static IEnumerable<Row> ReadCsvRows(string fileName)
{
   using var reader = new CsvReader(fileName);
   while (reader.ReadNext())
   {
      yield return reader.CurrentRow;
   }
}

在这种情况下,如果第一个序列没有行,甚至 new CsvReader(fileName) 也不会被调用。