127

リストが空であるかどうかを判断するための「最良の」(速度と読みやすさの両方を考慮した)方法は何ですか?リストがタイプIEnumerable<T>であり、Countプロパティがない場合でも。

今、私はこれの間で投げています:

if (myList.Count() == 0) { ... }

この:

if (!myList.Any()) { ... }

私の推測では、2番目のオプションは、最初のアイテムが表示されるとすぐに結果が返されるため、より高速ですが、2番目のオプション(IEnumerableの場合)は、カウントを返すためにすべてのアイテムにアクセスする必要があります。

そうは言っても、2番目のオプションはあなたにとって読みやすいように見えますか?どちらがいいですか?または、空のリストをテストするためのより良い方法を考えられますか?

@lassevkの応答を編集するのが最も論理的であるように思われ、可能であればキャッシュされたカウントを使用するためのランタイムチェックを少し組み合わせて次のようにします

public static bool IsEmpty<T>(this IEnumerable<T> list)
{
    if (list is ICollection<T>) return ((ICollection<T>)list).Count == 0;

    return !list.Any();
}
4

16 に答える 16

107

あなたはこれを行うことができます:

public static Boolean IsEmpty<T>(this IEnumerable<T> source)
{
    if (source == null)
        return true; // or throw an exception
    return !source.Any();
}

編集:基になるソースが実際に高速のCountプロパティを持っている場合、.Countメソッドを使用するだけで高速になることに注意してください。上記の有効な最適化は、いくつかの基本タイプを検出し、.Any()アプローチの代わりにそれらの.Countプロパティを使用することですが、保証ができない場合は.Any()にフォールバックします。

于 2008-09-03T08:38:51.650 に答える
14

私はあなたが落ち着いたように見えるコードに1つの小さな追加をします:ICollectionこれはいくつかの廃止されていないジェネリッククラス(すなわち、)によっても実装されているので、Queue<T>もチェックしてくださいStack<T>。また、より慣用的で高速であることが示されているasため、代わりに使用します。is

public static bool IsEmpty<T>(this IEnumerable<T> list)
{
    if (list == null)
    {
        throw new ArgumentNullException("list");
    }

    var genericCollection = list as ICollection<T>;
    if (genericCollection != null)
    {
        return genericCollection.Count == 0;
    }

    var nonGenericCollection = list as ICollection;
    if (nonGenericCollection != null)
    {
        return nonGenericCollection.Count == 0;
    }

    return !list.Any();
}
于 2010-08-26T15:17:13.230 に答える
8

LINQ 自体は、何らかの方法で Count() メソッドの周りで深刻な最適化を行っているに違いありません。

これはあなたを驚かせますか?IList実装の場合Count、要素の数を直接読み取るだけでAny、メソッドを照会しIEnumerable.GetEnumerator、インスタンスを作成して、MoveNext少なくとも 1 回呼び出す必要があると思います。

/EDIT @マット:

IEnumerable の Count() 拡張メソッドが次のようなことをしているとしか思えません。

はい、もちろんそうです。これが私が意味したことです。実際には、のICollection代わりに使用しますIListが、結果は同じです。

于 2008-09-03T09:25:50.910 に答える
6

簡単なテストを作成しました。これを試してください。

 IEnumerable<Object> myList = new List<Object>();

 Stopwatch watch = new Stopwatch();

 int x;

 watch.Start();
 for (var i = 0; i <= 1000000; i++)
 {
    if (myList.Count() == 0) x = i; 
 }
 watch.Stop();

 Stopwatch watch2 = new Stopwatch();

 watch2.Start();
 for (var i = 0; i <= 1000000; i++)
 {
     if (!myList.Any()) x = i;
 }
 watch2.Stop();

 Console.WriteLine("myList.Count() = " + watch.ElapsedMilliseconds.ToString());
 Console.WriteLine("myList.Any() = " + watch2.ElapsedMilliseconds.ToString());
 Console.ReadLine();

2番目はほぼ3倍遅いです:)

スタックや配列、またはその他のシナリオでストップウォッチテストを再試行すると、実際にはリストのタイプによって異なります。これは、カウントが遅いことが証明されているためです。

ですから、使用しているリストの種類によって異なると思います。

(指摘するだけで、2000以上のオブジェクトをリストに入れましたが、他のタイプとは逆に、カウントはさらに高速でした)

于 2008-09-03T08:39:30.400 に答える
6

List.CountMicrosoft のドキュメントによると O(1) です:
http://msdn.microsoft.com/en-us/library/27b47ht3.aspx

List.Count == 0クエリよりもはるかに高速です

これは、リストに何かが追加または削除されるたびに更新される Count というデータ メンバーがあるためです。そのため、呼び出したときにList.Countすべての要素を反復処理して取得する必要はなく、データ メンバーを返すだけです。

于 2010-08-16T16:37:53.153 に答える
3

複数のアイテムがある場合は、2 番目のオプションの方がはるかに高速です。

  • Any()アイテムが 1 つ見つかり次第返します。
  • Count()リスト全体を調べ続ける必要があります。

たとえば、列挙に 1000 個のアイテムがあるとします。

  • Any()最初のものをチェックしてから、true を返します。
  • Count()列挙全体をトラバースした後、1000 を返します。

述語オーバーライドの 1 つを使用すると、これはさらに悪化する可能性があります。一致するものが 1 つしかない場合でも、Count() はすべての項目をチェックする必要があります。

Any one の使用に慣れます - それは理にかなっていて読みやすいです。

1 つの注意点 - IEnumerable だけでなくリストがある場合は、そのリストの Count プロパティを使用します。

于 2008-09-03T09:05:49.167 に答える
3

@Konrad驚いたことに、私のテストでは、を受け入れるメソッドにリストを渡しているIEnumerable<T>ため、ランタイムは の Count() 拡張メソッドを呼び出してリストを最適化できませんIList<T>

IEnumerable の Count() 拡張メソッドが次のようなことをしているとしか思えません。

public static int Count<T>(this IEnumerable<T> list)
{
    if (list is IList<T>) return ((IList<T>)list).Count;

    int i = 0;
    foreach (var t in list) i++;
    return i;
}

... 言い換えれば、IList<T>.

/EDIT @Konrad +1 mate - あなたはそれがオンになっている可能性が高いことについて正しいICollection<T>.

于 2008-09-03T09:29:45.660 に答える
1

さて、これはどうですか?

public static bool IsEmpty<T>(this IEnumerable<T> enumerable)
{
    return !enumerable.GetEnumerator().MoveNext();
}

編集:誰かがすでにこのソリューションをスケッチしていることに気づきました。Any()メソッドがこれを行うと言われましたが、自分でやらないのはなぜですか?よろしく

于 2009-10-26T04:37:06.740 に答える
1

これは、これを Entity Framework で動作させるために重要でした。

var genericCollection = list as ICollection<T>;

if (genericCollection != null)
{
   //your code 
}
于 2011-12-15T21:48:16.143 に答える
0

述語を可能にする、Dan Taoの答えの私の実装は次のとおりです。

public static bool IsEmpty<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source == null) throw new ArgumentNullException();
    if (IsCollectionAndEmpty(source)) return true;
    return !source.Any(predicate);
}

public static bool IsEmpty<TSource>(this IEnumerable<TSource> source)
{
    if (source == null) throw new ArgumentNullException();
    if (IsCollectionAndEmpty(source)) return true;
    return !source.Any();
}

private static bool IsCollectionAndEmpty<TSource>(IEnumerable<TSource> source)
{
    var genericCollection = source as ICollection<TSource>;
    if (genericCollection != null) return genericCollection.Count == 0;
    var nonGenericCollection = source as ICollection;
    if (nonGenericCollection != null) return nonGenericCollection.Count == 0;
    return false;
}
于 2012-09-02T15:54:45.677 に答える
0

Count() で確認すると、Linq はデータベースで "SELECT COUNT(*).." を実行しますが、結果にデータが含まれているかどうかを確認する必要があるため、Count() の代わりに FirstOrDefault() を導入することにしました。

var cfop = from tabelaCFOPs in ERPDAOManager.GetTable<TabelaCFOPs>()

if (cfop.Count() > 0)
{
    var itemCfop = cfop.First();
    //....
}

var cfop = from tabelaCFOPs in ERPDAOManager.GetTable<TabelaCFOPs>()

var itemCfop = cfop.FirstOrDefault();

if (itemCfop != null)
{
    //....
}
于 2011-08-05T14:39:14.600 に答える
0
private bool NullTest<T>(T[] list, string attribute)

    {
        bool status = false;
        if (list != null)
        {
            int flag = 0;
            var property = GetProperty(list.FirstOrDefault(), attribute);
            foreach (T obj in list)
            {
                if (property.GetValue(obj, null) == null)
                    flag++;
            }
            status = flag == 0 ? true : false;
        }
        return status;
    }


public PropertyInfo GetProperty<T>(T obj, string str)

    {
        Expression<Func<T, string, PropertyInfo>> GetProperty = (TypeObj, Column) => TypeObj.GetType().GetProperty(TypeObj
            .GetType().GetProperties().ToList()
            .Find(property => property.Name
            .ToLower() == Column
            .ToLower()).Name.ToString());
        return GetProperty.Compile()(obj, str);
    }
于 2012-03-19T13:00:18.203 に答える
-1
List<T> li = new List<T>();
(li.First().DefaultValue.HasValue) ? string.Format("{0:yyyy/MM/dd}", sender.First().DefaultValue.Value) : string.Empty;
于 2012-05-02T07:45:03.067 に答える
-3

myList.ToList().Count == 0. それで全部です

于 2015-05-05T14:50:03.180 に答える