将linq join的左侧或右侧填充为相同行数

3
我的目标是创建一个列表,无论左列或右列更短,都有相同行数的列表。
考虑以下两个查询:
var result1 = (from f in list2
               join b in list1 on f.index equals b.index into bf
               from x in bf.DefaultIfEmpty()
               select new { box = (x == null ? String.Empty : x.b), file = f.f });

var result2 = (from b in list1
              join f in list2 on b.index equals f.index into bf
              from x in bf.DefaultIfEmpty()
              select new { l1 = x.f, l2 = (x == null ? String.Empty : b.b) });

其中一个在列表1上检查null并填充空字符串,另一个在列表2上检查null并填充空字符串。

我想找到一个两者都可能发生的例子。顺序不重要,只要左边的每个值或空字符串,在右边都有一个值或空字符串即可。

2个回答

5

看起来你需要一个版本的 IEnumerable.Zip 扩展方法,它不会在较短的列表达到其结尾时停止:

public static IEnumerable<TResult> ZipAll<T, TResult>(this IEnumerable<T> list1,
                                                           IEnumerable<T> list2,
                                                           Func<T, T, TResult> zipper,
                                                           T defaultValue = default(T))
{
    using (var enum1 = list1.GetEnumerator())
    {
        using (var enum2 = list2.GetEnumerator())
        {

            bool valid1, valid2;
            do
            {
                valid1 = enum1.MoveNext();
                valid2 = enum2.MoveNext();
                if (valid1 || valid2)
                {
                    var item1 = valid1 ? enum1.Current : defaultValue;
                    var item2 = valid2 ? enum2.Current : defaultValue;

                    yield return zipper(item1, item2);
                }
            }
            while (valid1 || valid2);

        }
    }
}

然后:

var result = list1.ZipAll(list2, (l1, l2) => new { l1, l2 }, string.Empty);

使用扩展功能得很出色。我一直在尝试用LINQ来完成全部,但这个方法真是太棒了。谢谢! - crthompson
是的,扩展方法很棒 :) - Sphinxxx

1
如果我正确理解了您的问题,那么您已经接近您想要的目标:

  • 将您的结果转换为匿名项目列表
  • 选择所有项目到新列表>
  • 将l1和l2放入新的列表中
  • 您需要使用SelectMany展开结果

扩展代码:

var result= (from f in list2
               join b in list1 on f.index equals b.index into bf
               from x in bf.DefaultIfEmpty()
               select new { l1 = (x == null ? String.Empty : x.b), l2 = f.f })
               .ToList().Select(li => new List<List<string>> 
                                            { 
                                                new List<string> 
                                                { 
                                                    li.l1, 
                                                    li.l2 
                                                } 
                                            }).ToList()
                                            .SelectMany (li => li).ToList();

这将提供一个包含字符串对象列表的列表,如下所示:

enter image description here


这对一侧完美运作,但对另一侧则不然。我会在我的帖子中更新一个另一侧的例子。 - crthompson
我的帖子可能太复杂了。我已经大大简化了它,如果您认为我应该添加任何内容,请告诉我。 - crthompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接