web-dev-qa-db-ja.com

シーケンスが空かどうかを確認するための推奨される方法

メソッドがシーケンスIEnumerable<T>を返すので、それが空かどうかを確認します。それをどのようにすすめますか?読みやすさとパフォーマンスの両方を求めています。

最初の最も明白な方法は、カウントがゼロより大きいことを確認することです。

if(sequence.Count() == 0)

読みやすさはまあまあですが、実際にシーケンス全体を実行する必要があるため、パフォーマンスはひどいものです。

私が時々使用する方法は次のとおりです。

if(!sequence.Any())

これは(私の知る限り)シーケンス全体を通過する必要はありませんが、読みやすさは少し逆で扱いにくいです。 (ただし、シーケンスがでない空であることを確認している場合は、はるかに読みやすくなります)。

別のオプションは、次のように、try-catchでFirstを使用することです。

try
{
    sequence.First();
}
catch(InvalidOperationException)
{
    // Do something
}

非常にきれいな解決策ではなく、例外などを使用しているため、おそらくもっと遅くなります。もちろんFirstOrDefaultを使用することでそれを防ぐことができますが、シーケンスの最初の項目が実際にwasである場合に大きな問題が発生します値;)

それで、シーケンスが空かどうかを確認する他の方法はありますか?どちらを普段使いますか?どちらを使用することをお勧めしますか?

注:読みやすくするために、おそらく上記のスニペットの1つをIsEmpty拡張メソッドですが、そのメソッド内でも何かをしなければならないので、私はまだ興味があります:p

47
Svish

個人的には!sequence.Any()を使用します。

本当にが必要な場合は、いつでも独自の拡張メソッドを作成できます。

public static bool IsEmpty<T>(this IEnumerable<T> source)
{
    return !source.Any();
}

それからあなたは書くことができます:

if (sequence.IsEmpty())
81
Jon Skeet

この実装を使用して、拡張メソッドを作成できます。

public static bool IsEmpty<T>(this IEnumerable<T> items) {
        using (var enumerator = items.GetEnumerator())
        {
            return !enumerator.MoveNext();
        }
 }
6

呼び出しているこれらすべてのメソッドはLINQ拡張メソッドであるため、LINQプロバイダーの実装方法によって異なります。シーケンスが空かどうかを知りたい場合は、Count() == 0またはAny() == falseが適切です。私はAny()を好みます。

ただし、sequenceが実際のTypeによっては、LINQ拡張メソッドを使用する必要がない場合があります。つまり配列の場合は、sequence.Lengthを呼び出すことができます。コレクションの場合は、sequence.Countを使用できます。

2
Neil Barnwell

この拡張メソッドを使用して、シーケンスがnullであるか、アイテムがないかを検出します。また、string.IsNullOrEmpty()メソッドのように、シーケンスに少なくとも1つのアイテムがあるかどうかを検出します。

 public static bool IsNullOrEmpty<TSource>(this IEnumerable<TSource> source) {
     if (source == null) {
        return true;
     }

     return !source.Any();
 }

 public static bool IsNotNullOrEmpty<TSource>(this IEnumerable<TSource> source) {
     return !source.IsNullOrEmpty();
 }
 .
 .
 .
 if (!sequence.IsNullOrEmpty()) {
     //Do Something with the sequence...
 }
0
Sagi

あなたが言った:

if(sequence.Count() == 0)読みやすさはまともですが、実際にシーケンス全体を実行する必要があるため、パフォーマンスはひどいものです。

それは本当ですか?あなたはInterfaceIEnumerable<T>の扱いについて話しているが、その実装に関して、真である場合とそうでない場合があると仮定している。実際、私が長年にわたって作成してきたカスタムコレクションの多くは、現在のカウントを内部的に格納するプライベート変数を保持しています。つまり、.Countを返すことは、コレクション全体を繰り返す必要がない簡単な問題です。

つまり、特定の実装が.Countに対して最適化されていないことがわかっている場合を除き、.Countを使用します。可能な限り早期の最適化を避け、読みやすさを維持します。

0
Nick

私が時々使用する方法は次のとおりです。

if(!sequence.Any())

 これは(私の知る限り)シーケンス全体を実行する必要はありません。  しかし、読みやすさは少し後ろ向きで扱いにくいです。 (ただし、シーケンスが空でないことを確認している場合は、読み取りが大幅に向上します)。

  1. Microsoftによれば、 任意 は実際にしないでシーケンス全体を通過する必要があります。セクションからの引用備考

sourceの列挙は、結果を判別できるとすぐに停止されます。

  1. これは、if-elseステートメント内の要素の存在をテストする場合に特に当てはまります。おそらく、読みやすさは、ifステートメントの要素の存在とelseの要素の不在をテストして、!演算子の使用を回避する場合に最適です。

    if (sequence.Any())
    {
    }
    else
    {
    }
    

    ほとんどの人はそれをもっと読みやすいと考えています:

    if (!sequence.Any())
    {
    }
    else
    {
    }
    
0
DavidRR