如果长度恰好为1,我怎样才能获得IEnumerable的第一个值,否则默认值为默认值?

时间:2017-02-19 04:48:01

标签: c# linq generics ienumerable extension-methods

我想要像length != 1这样的内容,但我希望v.Count() == 1 ? v[0] : default返回默认值。像{{1}}这样的东西。但我更愿意在不将整个枚举转换为数组的情况下完成它。获得这种行为的最佳方法是什么?

3 个答案:

答案 0 :(得分:9)

Microsoft的Enumerable.FirstOrDefault实现直接与底层枚举器一起工作。你也可以:

public static T FirstIfOnlyOne<T>(this IEnumerable<T> source, T defaultValue = default(T))
{
    // (Null check and IList<T> optimization omitted...)

    using (IEnumerator<T> enumerator = source.GetEnumerator())
    {
        if (enumerator.MoveNext()) // Is there at least one item?
        {
            T item = enumerator.Current; // Save it.
            if (!enumerator.MoveNext()) // Is that it?
                return item;
        }
    }
    return defaultValue;
}

这可能是最有效的实施方式。

答案 1 :(得分:7)

最好避免多次迭代枚举,因为并非所有枚举都重复相同的值。

为了确保您的枚举只返回1个元素,从枚举中获取前两个元素并将结果转换为数组是最有效的。如果数组有两个元素,你知道可枚举有多个元素而不迭代整个可枚举。可枚举可能无限长。

所以这是如何做到的:

public static T OneOnlyThenFirstOrDefault<T>(this IEnumerable<T> source)
{
    var beginning = source.Take(2).ToArray();
    return beginning.Length == 1 ? beginning[0] : default(T);
}

答案 2 :(得分:0)

您是否尝试过编写自定义扩展方法,例如:

public static TSource MyFirstOrDefault<TSource>(this IEnumerable<TSource> source)
{
    return source.Count() == 1 ? source.First() : default(TSource);
}

但是你需要记住,方法Count()First()需要实例化内部元素集合才能获得计数(或第一个元素)。

希望,这对你有帮助。