在C#中,使用Linq,如果我想判断一个集合是否有任何元素,我可以这样做:

someCollection.Any()

哪一个比

someCollection.Count() > 0

因为后者会计算集合中的所有项目,所以当我并不真正关心有多少项目时,我只想知道是否有项目.

是否有用于判断集合是否包含多个项的类似功能?类似于:

someCollection.Many()

而不是必须做

someCollection.Count() > 1

我知道这是个愚蠢的问题,而且从我的研究来看,看起来没有这个问题.但由于这是我经常使用的东西,我想我应该和社区重新核实一下.

谢谢

推荐答案

根据我的 comments :

首先,您应该判断IEnumerable<T> sourceactually isIReadOnlyCollection<T>还是ICollection<T>,因为它有一个您可以使用的.Count属性--这比任何迭代都更可取.

假设您的IEnumerable<T>没有O(1) .Count属性,如果您想查看是否有at least 1元素(即"at least 2 or more"),则使用source.Take(2).Count() == 2source.Skip(1).Any().

如下所示:

public static Boolean Many<T>( this IEnumerable<T> source )
{
    if( source is null ) throw new ArgumentNullException(nameof(source));

    if( source is ICollection<T> col ) return col.Count >= 2;
    else if( source is IReadOnlyCollection<T> roCol ) return roCol.Count >= 2;

    return source.Take(2).Count() == 2;
}

如果你想提高效率,可以进行手动迭代:

public static Boolean Many<T>( this IEnumerable<T> source )
{
    if( source is null ) throw new ArgumentNullException(nameof(source));

    if( source is ICollection<T> col ) return col.Count >= 2;
    else if( source is IReadOnlyCollection<T> roCol ) return roCol.Count >= 2;

    Int32 count = 0;
    using( IEnumerator<T> iter = source.GetEnumerator() )
    {
        while( iter.MoveNext() && count < 2 )
        {
            count += 1;
        }
    }

    return count == 2;
}

如果你想提高even more的效率,允许消费者提供非盒装的枚举数(例如List<T>.Enumerator):

public static Boolean Many<TEnumerable,TEnumerator,TElement>( /*this*/ TEnumerable source, Func<TEnumerable,TEnumerator> getEnumerator )
    where TEnumerable : IEnumerable<TElement>
    where TEnumerator : IEnumerator<TElement>
{
    if( source        is null ) throw new ArgumentNullException(nameof(source));
    if( getEnumerator is null ) throw new ArgumentNullException(nameof(getEnumerator));
    
    //

    if     ( source is ICollection<TElement>           col ) return col  .Count >= 2;
    else if( source is IReadOnlyCollection<TElement> roCol ) return roCol.Count >= 2;

    Int32 count = 0;
    using( TEnumerator iter = getEnumerator( source ) )
    {
        while( iter.MoveNext() && count < 2 )
        {
            count += 1;
        }
    }

    return count == 2;
}

用法如下:

List<String> listOfStrings = new List<String>() { ... };

if( listOfStrings.Many</*TEnumerable:*/ List<String>, /*TEnumerator:*/ List<String>.Enumerator, /*TElement:*/ String >( l => l.GetEnumerator() ) )
{
    
}
  • 是的,很难看……不幸的是,它是but C# still doesn't support this level of generic type-inference-也不支持partial generic parameter application.
  • list.GetEnumerator()部分是必需的,因为它是将基于struct的枚举数传递到泛型代码中而无需装箱(至少不是没有反射)的唯一方法.

Csharp相关问答推荐

为什么使用DXGI输出复制和Direct 3D时捕获的图像数据全为零?

Monty Hall游戏节目模拟给我50/50的结果

如何使用while循环实现异常处理

实体框架核心上是否支持使用NPGSQL的字符串聚合?

为什么将鼠标悬停在DateTimeOffset上只显示Hour值?

如何在C#中将方法/线程启动传递给基本构造函数

未在数据流块之间传播完成

将类移动到新命名空间后更新RavenDB Raven-Clr-Type

自定义列表按字符串的部分排序

为什么@rendermode Interactive Auto不能在.NET 8.0 Blazor中运行?

Blazor Fluent UI DialogService,<;FluentDialogProvider/>;错误

JsonPath在Newtonsoft.Json';S实现中的赋值

如何强制新设置在Unity中工作?

使用Blazor WebAssembly提高初始页面加载时间的性能

Maui:更改代码中的绑定字符串不会更新UI,除非重新生成字符串(MVVM)

使用DI实例化带有动态参数的服务?

Azure队列触发器未使用隔离的工作进程执行

避免在特定区域中设置Visual Studio代码的自动格式

HttpClient,上传文件时实现进度

将两个JSON文件与覆盖值的主文件合并