[英]How do I check if IEnumerable has a single element?
Count()
掃描所有元素,因此如果 enumerable 包含很多元素, if (list.Count() == 1)
將不會表現良好。
如果不完全是一個元素, Single()
會拋出異常。 使用try { list.Single(); } catch(InvalidOperationException e) {}
try { list.Single(); } catch(InvalidOperationException e) {}
既笨拙又低效。
如果有多個元素, SingleOrDefault()
會拋出異常,因此if (list.SingleOrDefault() == null)
(假設TSource
是引用類型)將不適用於大小大於 1 的枚舉。
var exactlyOne = sequence.Take(2).Count() == 1;
如果元素較少, Take
擴展方法不會拋出,它只會返回可用的元素。
更直接:
public static bool HasSingle<T>(this IEnumerable<T> sequence) {
if (sequence is ICollection<T> list) return list.Count == 1; // simple case
using(var iter = sequence.GetEnumerator()) {
return iter.MoveNext() && !iter.MoveNext();
}
}
但是請注意,你只能保證你可以閱讀的順序一次,所以在這種情況下:通過檢查,有一個項目一個簡單的事實,你不能再獲得該項目。 因此,如果有的話,您可能更喜歡能給您帶來價值的東西:
public static bool HasSingle<T>(this IEnumerable<T> sequence, out T value)
{
if (sequence is IList<T> list)
{
if(list.Count == 1)
{
value = list[0];
return true;
}
}
else
{
using (var iter = sequence.GetEnumerator())
{
if (iter.MoveNext())
{
value = iter.Current;
if (!iter.MoveNext()) return true;
}
}
}
value = default(T);
return false;
}
為了避免其他答案中的額外迭代,您可以實現自己的擴展:
public static bool HasExactlyOneElement<T>(this IEnumerable<T> source)
{
using (var enumerator = source.GetEnumerator())
return enumerator.MoveNext() && !enumerator.MoveNext();
}
您可以使用!Skip(1).Any()
:
bool contains1 = items.Any() && !items.Skip(1).Any();
如果類型是集合,您可以創建一個更有效的擴展:
public static bool ContainsCountItems<TSource>(this IEnumerable<TSource> source, int count)
{
ICollection<TSource> collectionoft = source as ICollection<TSource>;
if (collectionoft != null) return collectionoft.Count == count;
ICollection collection = source as ICollection;
if (collection != null) return collection.Count == count;
int itemCount = 0;
using (IEnumerator<TSource> e = source.GetEnumerator())
{
checked
{
while (e.MoveNext() && ++itemCount <= count)
{
if (itemCount == count)
return !e.MoveNext();
}
}
}
return false;
}
用法:
var items = Enumerable.Range(0, 1);
bool contains1 = items.ContainsCountItems(1); // true;
items = Enumerable.Range(0, 2);
contains1 = items.ContainsCountItems(1); // false;
您可以將此擴展用於任何類型和任何數量,因此不僅是 1
var items = Enumerable.Range(0, 10);
bool contains10 = items.ContainsCountItems(10); // true;
我建議玩Any
,我們必須檢查一下
list
至少有一項 - Any
list
沒有第二項 - !list.Skip(1).Any()
代碼:
bool isSingle = list.Any() && !list.Skip(1).Any();
然而,這種方法有缺點:它掃描list
兩次,這在IQueryable
情況下可能是一個問題(查詢執行兩次,結果可能不同,額外開銷)
您在原始枚舉上調用的每個 Linq 方法調用( .Skip()
.Any()
、 .Skip()
、...)都會創建一個枚舉器,根據您的要求,這也可能對性能造成相當大的影響。
所以你可以使用.Take(2).Count() == 1
。
如果您出於某種原因不想使用 Linq,您也可以手動使用Enumerator :
/// <summary>
/// Checks that the IEnumerable<T> has exactly one item
/// </summary>
public static bool HasSingleElement<T>(IEnumerable<T> value)
{
using ( var enumerator = value.GetEnumerator() )
{
// Try to get first element - return false if that doesn't exist
if ( !enumerator.MoveNext() )
return false;
// Try to get second element - return false if it does exist
if ( enumerator.MoveNext() )
return false;
// exactly one element exists
return true;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.