如何获得IEnumerable的第一个值,如果长度恰好为1,或者默认情况下为其他值?
我想要的东西像IEnumerable.FirstOrDefault
,但我想如果length != 1
返回的默认值。类似于v.Count() == 1 ? v[0] : default
。但我宁愿这样做,而不将整个枚举转换为数组。得到这种行为的最好方法是什么?如何获得IEnumerable的第一个值,如果长度恰好为1,或者默认情况下为其他值?
避免迭代枚举不止一次是个好主意,因为并非所有枚举都重复相同的值。
为了确保您的枚举只返回1个元素,从enumerable中获取前两个元素并将结果转换为数组是最有效的。如果数组有两个元素,那么您知道枚举具有多个元素,而不会遍历整个枚举。一个枚举可能无限长。
因此,这里是如何做到这一点:
public static T OneOnlyThenFirstOrDefault<T>(this IEnumerable<T> source)
{
var beginning = source.Take(2).ToArray();
return beginning.Length == 1 ? beginning[0] : default(T);
}
你有没有试着写一个自定义的扩展方法是这样的:
public static TSource MyFirstOrDefault<TSource>(this IEnumerable<TSource> source)
{
return source.Count() == 1 ? source.First() : default(TSource);
}
,但你必须记住,方法Count()
和First()
将需要实例元素的内集合,以获得计数(或第一个元素)。
希望,那会帮助你。
这会引发异常。计数为零时没有第一项。除此之外,源有两个项目时返回什么值? –
@RuardvanElburg - 谢谢你的提示(我修正了错字)。 – MaKCbIMKo
微软的落实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;
}
这可能是最有效的实现方式。
我认为这是最好的答案。 – Bigeyes
正在转换为数组必要吗?基于[这个相关问题的答案](http://*.com/a/1993398/2137382)我想你可以检查'Take(2).Count()== 1',如果是的话,返回'source.Single()'。 –
@JoeSewell - 转换为数组是必要的。如果你做'.Take(2).Count()',然后'.Single()'你迭代枚举两次,并且不能保证每次枚举总是产生相同的值。 – Enigmativity
一些枚举可能甚至会在第二次失败。 –