1

MoreLinq 提供了 FullJoin 扩展。但是,我希望 bothSelector 函数(它是 FullJoin 函数的参数)仅在 TResult 不为空时才返回它。

例子:

给定两个完全由数字连接的列表:

清单 1:1,2,3 清单 2:1,2,3,4,5

结果列表 3:空、空、空、4、5

所需:4、5

    public void X()
    {
        var list1 = new List<int> { 1, 2, 3, 4, 5 };
        var list2 = new List<int> { 4, 5 };

        list1.FullJoin(
            list2, 
            item => item, 
            item1 => item1, 
            item2 => item2, 
            (item1, item2) => item1);


    }

这可能吗?

谢谢。

4

1 回答 1

0

使用原始 FullJoin 代码稍作修改:

    /// <summary>
    /// Full join without returning null values.
    /// MoreLinq - https://github.com/morelinq/MoreLINQ/blob/master/MoreLinq/FullJoin.cs
    /// </summary>
    public static IEnumerable<TResult> FullJoinExceptNull<TFirst, TSecond, TKey, TResult>(
        this IEnumerable<TFirst> first,
        IEnumerable<TSecond> second,
        Func<TFirst, TKey> firstKeySelector,
        Func<TSecond, TKey> secondKeySelector,
        Func<TFirst, TResult> firstSelector,
        Func<TSecond, TResult> secondSelector,
        Func<TFirst, TSecond, TResult> bothSelector,
        IEqualityComparer<TKey> comparer = null)
    {
        if (first == null) throw new ArgumentNullException(nameof(first));
        if (second == null) throw new ArgumentNullException(nameof(second));
        if (firstKeySelector == null) throw new ArgumentNullException(nameof(firstKeySelector));
        if (secondKeySelector == null) throw new ArgumentNullException(nameof(secondKeySelector));
        if (firstSelector == null) throw new ArgumentNullException(nameof(firstSelector));
        if (secondSelector == null) throw new ArgumentNullException(nameof(secondSelector));
        if (bothSelector == null) throw new ArgumentNullException(nameof(bothSelector));

        return _(); IEnumerable<TResult> _()
        {
            var seconds = second.Select(e => new KeyValuePair<TKey, TSecond>(secondKeySelector(e), e)).ToArray();
            var secondLookup = seconds.ToLookup(e => e.Key, e => e.Value, comparer);
            var firstKeys = new HashSet<TKey>(comparer);

            foreach (var fe in first)
            {
                var key = firstKeySelector(fe);
                firstKeys.Add(key);

                using var se = secondLookup[key].GetEnumerator();

                if (se.MoveNext())
                {
                    do 
                    {
                        var result = bothSelector(fe, se.Current);
                        if (result == null) continue;
                        yield return result; 
                    }
                    while (se.MoveNext());
                }
                else
                {
                    se.Dispose();
                    yield return firstSelector(fe);
                }
            }

            foreach (var se in seconds)
            {
                if (!firstKeys.Contains(se.Key))
                    yield return secondSelector(se.Value);
            }
        }
    }
于 2020-02-03T09:40:53.280 回答