wake-up-neo.com

Unterschied zwischen IEnumerable Count () und Length

Was sind die Hauptunterschiede zwischen IEnumerableCount() und Length?

58
balalakshmi

Wenn Sie Count für IEnumerable<T> Aufrufen, nehmen wir an, Sie beziehen sich auf die Erweiterungsmethode Count für System.Linq.Enumerable. Length ist keine Methode für IEnumerable<T>, sondern eine Eigenschaft für Array-Typen in .NET wie int[].

Der Unterschied liegt in der Leistung. Die Length -Eigenschaft ist garantiert eine O(1)- Operation. Die Komplexität der Count -Erweiterungsmethode hängt vom Laufzeittyp des Objekts ab Versuchen Sie, mehrere Typen zu konvertieren, die die O(1) Längen-Suche wie ICollection<T> über eine Count -Eigenschaft unterstützen. Wenn keine verfügbar sind, werden alle Elemente aufgelistet und zähle sie, die eine Komplexität von O (N) haben.

Beispielsweise

int[] list = CreateSomeList();
Console.WriteLine(list.Length);  // O(1)
IEnumerable<int> e1 = list;
Console.WriteLine(e1.Count()); // O(1) 
IEnumerable<int> e2 = list.Where(x => x <> 42);
Console.WriteLine(e2.Count()); // O(N)

Der Wert e2 Wird als C # -Iterator implementiert, der die Zählung von O(1) nicht unterstützt, und daher muss die Methode Count die gesamte Sammlung auflisten, um zu bestimmen, wie lang ist es.

87
JaredPar

Kleiner Zusatz zu Jon Skeet s Kommentar.

Hier ist der Quellcode der Count() -Erweiterungsmethode:

.NET 3:

public static int Count<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    ICollection<TSource> is2 = source as ICollection<TSource>;
    if (is2 != null)
    {
        return is2.Count;
    }
    int num = 0;
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            num++;
        }
    }
    return num;
}

.NET 4:

public static int Count<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    ICollection<TSource> is2 = source as ICollection<TSource>;
    if (is2 != null)
    {
        return is2.Count;
    }
    ICollection is3 = source as ICollection;
    if (is3 != null)
    {
        return is3.Count;
    }
    int num = 0;
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            num++;
        }
    }
    return num;
}
21
bniwredyc
  • Länge ist eine feste Eigenschaft, z.B. eines eindimensionalen Arrays oder Strings. Es ist also keine Zähloperation erforderlich (bei mehrdimensionalen Arrays wird die Größe aller Dimensionen multipliziert). O(1) hier bedeutet, dass die Abrufzeit immer gleich ist, egal wie viele Elemente es gibt. Eine lineare Suche wäre (im Gegensatz dazu) O (n).

  • Die Count-Eigenschaft für ICollections (z. B. List und List <T>) kann geändert werden. Sie muss daher entweder bei Hinzufügen/Entfernen-Vorgängen aktualisiert werden oder wenn Count angefordert wird, nachdem die Collection geändert wurde. Hängt von der Implementierung des Objekts ab.

  • Die Count () - Methode von LINQ iteriert grundsätzlich JEDES MAL, wenn sie aufgerufen wird (außer wenn das Objekt ein ICollection-Typ ist, wird die ICollection.Count-Eigenschaft angefordert).

Beachten Sie, dass IEnumerables häufig nicht bereits definierte Objektsammlungen sind (wie Listen, Arrays, Hashtables usw.), sondern Verknüpfungen zu Hintergrundoperationen, die Ergebnisse generieren, wenn sie angefordert werden (als verzögerte Ausführung bezeichnet).

In der Regel haben Sie eine SQL-ähnliche LINQ-Anweisung wie diese (die typische Anwendung der verzögerten Ausführung):

IEnumerable<Person> deptLeaders = 
   from p in persons
   join d in departments
      on p.ID equals d.LeaderID
   orderby p.LastName, p.FirstName
   select p;

Dann gibt es folgenden Code:

if (deptLeaders.Count() > 0)
{
   ReportNumberOfDeptLeaders(deptLeaders.Count());
   if (deptLeaders.Count() > 20)
      WarnTooManyDepartmentLeaders(deptLeaders.Count());
}

Wenn also eine Warnung für zu viele Abteilungsleiter ausgegeben wird, durchsucht .NET die Personen VIER MAL, vergleicht sie mit den Abteilungsleitern, sortiert sie nach Namen und zählt dann die Ergebnisobjekte.

Und das nur, wenn Personen und Abteilungen Vorgabewertesammlungen sind, nicht Abfragen selbst.

1
Erik Hart