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

Voi*_*tar 2 c# linq generics ienumerable extension-methods

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

Mic*_*Liu 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;
}
Run Code Online (Sandbox Code Playgroud)

这可能是最有效的实施方案.


Eni*_*ity 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);
}
Run Code Online (Sandbox Code Playgroud)

  • @JoeSewell - 转换为数组是必要的.如果你做`.Take(2).Count()`然后`.Single()`你正在迭代可枚举两次,并且不能保证枚举每次都会产生相同的值. (3认同)
  • 有些枚举可能第二次失败. (2认同)