Enumerable.Zip强制执行相同的长度

时间:2015-03-13 19:15:44

标签: c# linq

我发现自己经常需要使用Enumerable.Zip(),但要确保两个IEnumerable具有相同的长度(或两者都是无限的)。例如,如果一个可枚举到达终点但另一个没有,我希望它抛出。根据{{​​3}},Zip()只要其中一个结束就会停止枚举。

我最终总是需要下面这样的东西。什么是最“内置”/优雅的方式来解决这个问题?

void Foo(IEnumerable<int> a, IEnumerable<int> b)
{
    // caching them. they are not huge or infinite in my scenario
    var a = a.ToList();
    var b = b.ToList();

    if (a.Count() != b.Count())
    {
        throw ...;
    }

    Enumerable.Zip(a, b, ...);
}

1 个答案:

答案 0 :(得分:12)

我可能只是按照你想要的方式重新实现Zip。这非常简单 - 以下内容可以从MoreLINQ中轻松改编。你会想给它一个更好的名字,请注意......

public static IEnumerable<TResult> ZipForceEqual<TFirst, TSecond, TResult>(
    this IEnumerable<TFirst> first,
    IEnumerable<TSecond> second,
    Func<TFirst, TSecond, TResult> resultSelector)
{
    if (first == null) throw new ArgumentNullException("first");
    if (second == null) throw new ArgumentNullException("second");
    if (resultSelector == null) throw new ArgumentNullException("resultSelector");

    return ZipForceEqualImpl(first, second, resultSelector);
}

static IEnumerable<TResult> ZipForceEqualImpl<TFirst, TSecond, TResult>(
    IEnumerable<TFirst> first,
    IEnumerable<TSecond> second,
    Func<TFirst, TSecond, TResult> resultSelector)
{
    using (var e1 = first.GetEnumerator())
    using (var e2 = second.GetEnumerator())
    {
        while (e1.MoveNext())
        {
            if (e2.MoveNext())
            {
                yield return resultSelector(e1.Current, e2.Current);
            }
            else
            {
                throw new InvalidOperationException("Sequences differed in length");
            }
        }
        if (e2.MoveNext())
        {
            throw new InvalidOperationException("Sequences differed in length");
        }
    }
}