Policzyć przedmioty z liczby mnogiej bez iteracji?

private IEnumerable<string> Tables
{
    get
    {
        yield return "Foo";
        yield return "Bar";
    }
}

Powiedzmy, że chcę iterate na tych i napisać coś takiego jak przetwarzanie #n Z # m.

Czy Jest jakiś sposób, aby dowiedzieć się wartości m bez iteracji przed moją główną iteracją?

Mam nadzieję, że wyraziłem się jasno.
Author: Erik Philips, 2008-10-04

19 answers

IEnumerable nie popiera tego. To z założenia. IEnumerable używa leniwej oceny, aby uzyskać elementy, o które prosisz tuż przed ich potrzebą.

Jeśli chcesz znać liczbę elementów bez iteracji nad nimi, możesz użyć ICollection<T>, ma ona właściwość Count.

 279
Author: Mendelt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-03 03:02:20

Metoda rozszerzenia System.Linq.Enumerable.Count na IEnumerable<T> ma następującą implementację:

ICollection<T> c = source as ICollection<TSource>;
if (c != null)
    return c.Count;

int result = 0;
using (IEnumerator<T> enumerator = source.GetEnumerator())
{
    while (enumerator.MoveNext())
        result++;
}
return result;

Więc próbuje rzucić do ICollection<T>, który ma właściwość Count i używa tego, jeśli to możliwe. W przeciwnym razie iteruje.

Więc najlepiej jest użyć metody rozszerzenia Count() na swoim obiekcie IEnumerable<T>, ponieważ w ten sposób uzyskasz najlepszą możliwą wydajność.

 175
Author: Daniel Earwicker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-02 01:20:57

Dodam jeszcze jakieś info:

Rozszerzenie Count() nie zawsze jest iteracyjne. Rozważ LINQ do Sql, gdzie licznik trafia do bazy danych, ale zamiast przywracać wszystkie wiersze, wydaje polecenie SQL Count() i zwraca ten wynik.

Dodatkowo kompilator (lub runtime) jest na tyle inteligentny, że wywoła metodę objects Count(), jeśli taką posiada. Więc to nie jak mówią inni, bycie całkowicie ignorantem i zawsze powtarzanie, aby liczyć żywioły.

W wielu przypadkach, gdy programista tylko sprawdza if( enumerable.Count != 0 ) używając metody rozszerzenia Any(), jak w if( enumerable.Any() ) jest o wiele bardziej wydajny z leniwą oceną linq, ponieważ może zwarć, gdy może określić, że są jakieś elementy. Jest również bardziej czytelny

 77
Author: Robert Paulson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-29 17:18:31

Liczba nie może liczyć bez iteracji.

W "normalnych" okolicznościach, klasy implementujące IEnumerable lub IEnumerable, takie jak List, mogłyby zaimplementować metodę Count zwracając listę.Policz własność. Jednak metoda Count nie jest w rzeczywistości metodą zdefiniowaną na interfejsie IEnumerable lub IEnumerable. (Jedynym, który jest w rzeczywistości, jest GetEnumerator.), A to oznacza, że implementacja specyficzna dla danej klasy nie może być to.

Raczej Count jest to metoda rozszerzenia, zdefiniowana na statycznej klasie Enumerable. Oznacza to, że może być wywołana na dowolnej instancji klasy pochodnej IEnumerable, niezależnie od implementacji tej klasy. Ale oznacza to również, że jest zaimplementowany w jednym miejscu, poza którąkolwiek z tych klas. Co oczywiście oznacza, że musi być zaimplementowane w sposób całkowicie niezależny od tych klas. Jedynym takim sposobem liczenia jest iteracja.

 10
Author: Chris Ammerman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-03 21:40:29

Mój przyjaciel ma serię postów na blogu, które dostarczają ilustracji, dlaczego nie możesz tego zrobić. Tworzy funkcję, która zwraca liczbę mnogą, gdzie każda iteracja zwraca następną liczbę pierwszą, aż do ulong.MaxValue, a następny element nie jest obliczany, dopóki o niego nie poprosisz. Szybkie, pop pytanie: ile przedmiotów jest zwracanych?

Tutaj są posty, ale są trochę długie:

  1. Beyond Loops (zapewnia początkową klasę Enumerable, używaną w drugiej posts)
  2. Applications of Iterate (Initial implementation)
  3. szalone metody rozszerzania: ToLazyList (Optymalizacja wydajności)
 9
Author: Joel Coehoorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-04 15:10:07

Nie, Nie w ogóle. Jednym z punktów korzystania z wyliczeń jest to, że rzeczywisty zbiór obiektów w wyliczeniu nie jest znany (z góry, lub nawet w ogóle).

 8
Author: JesperE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-03 21:07:40

Możesz użyć systemu.Linq.

using System;
using System.Collections.Generic;
using System.Linq;

public class Test
{
    private IEnumerable<string> Tables
    {
        get {
             yield return "Foo";
             yield return "Bar";
         }
    }

    static void Main()
    {
        var x = new Test();
        Console.WriteLine(x.Tables.Count());
    }
}

Otrzymasz wynik '2'.

 8
Author: prosseek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-26 19:02:13

Alternatywnie możesz wykonać następujące czynności:

Tables.ToList<string>().Count;
 7
Author: Anatoliy Nikolaev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-24 05:50:43

Wychodząc poza twoje bezpośrednie pytanie (na które dokładnie odpowiedziałeś negatywnie), jeśli chcesz zgłosić postęp podczas przetwarzania wyliczenia, możesz zajrzeć do mojego posta na blogu raportowanie postępu podczas zapytań Linq .

Pozwala ci to zrobić:

BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += (sender, e) =>
      {
          // pretend we have a collection of 
          // items to process
          var items = 1.To(1000);
          items
              .WithProgressReporting(progress => worker.ReportProgress(progress))
              .ForEach(item => Thread.Sleep(10)); // simulate some real work
      };
 5
Author: Samuel Jack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-12 15:56:18

Użyłem takiego sposobu wewnątrz metody, aby sprawdzić przekazaną w IEnumberable treść

if( iEnum.Cast<Object>().Count() > 0) 
{

}

Wewnątrz takiej metody:

GetDataTable(IEnumberable iEnum)
{  
    if (iEnum != null && iEnum.Cast<Object>().Count() > 0) //--- proceed further

}
 4
Author: Shahidul Haque,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-29 07:46:52

To zależy od wersji. Net i implementacji Twojego obiektu. Microsoft naprawił liczbę mnogą.Metoda Count do sprawdzania implementacji i używa ICollection.Count lub ICollection.Count, zobacz szczegóły tutaj https://connect.microsoft.com/VisualStudio/feedback/details/454130

I poniżej jest MSIL z Ildasm dla systemu.Rdzeń, w którym System.Linq rezyduje.

.method public hidebysig static int32  Count<TSource>(class 

[mscorlib]System.Collections.Generic.IEnumerable`1<!!TSource> source) cil managed
{
  .custom instance void System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       85 (0x55)
  .maxstack  2
  .locals init (class [mscorlib]System.Collections.Generic.ICollection`1<!!TSource> V_0,
           class [mscorlib]System.Collections.ICollection V_1,
           int32 V_2,
           class [mscorlib]System.Collections.Generic.IEnumerator`1<!!TSource> V_3)
  IL_0000:  ldarg.0
  IL_0001:  brtrue.s   IL_000e
  IL_0003:  ldstr      "source"
  IL_0008:  call       class [mscorlib]System.Exception System.Linq.Error::ArgumentNull(string)
  IL_000d:  throw
  IL_000e:  ldarg.0
  IL_000f:  isinst     class [mscorlib]System.Collections.Generic.ICollection`1<!!TSource>
  IL_0014:  stloc.0
  IL_0015:  ldloc.0
  IL_0016:  brfalse.s  IL_001f
  IL_0018:  ldloc.0
  IL_0019:  callvirt   instance int32 class [mscorlib]System.Collections.Generic.ICollection`1<!!TSource>::get_Count()
  IL_001e:  ret
  IL_001f:  ldarg.0
  IL_0020:  isinst     [mscorlib]System.Collections.ICollection
  IL_0025:  stloc.1
  IL_0026:  ldloc.1
  IL_0027:  brfalse.s  IL_0030
  IL_0029:  ldloc.1
  IL_002a:  callvirt   instance int32 [mscorlib]System.Collections.ICollection::get_Count()
  IL_002f:  ret
  IL_0030:  ldc.i4.0
  IL_0031:  stloc.2
  IL_0032:  ldarg.0
  IL_0033:  callvirt   instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<!!TSource>::GetEnumerator()
  IL_0038:  stloc.3
  .try
  {
    IL_0039:  br.s       IL_003f
    IL_003b:  ldloc.2
    IL_003c:  ldc.i4.1
    IL_003d:  add.ovf
    IL_003e:  stloc.2
    IL_003f:  ldloc.3
    IL_0040:  callvirt   instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
    IL_0045:  brtrue.s   IL_003b
    IL_0047:  leave.s    IL_0053
  }  // end .try
  finally
  {
    IL_0049:  ldloc.3
    IL_004a:  brfalse.s  IL_0052
    IL_004c:  ldloc.3
    IL_004d:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0052:  endfinally
  }  // end handler
  IL_0053:  ldloc.2
  IL_0054:  ret
} // end of method Enumerable::Count
 3
Author: prabug,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-29 00:13:02

Oto wielka dyskusja na temat leniwej oceny i odroczonej realizacji . Zasadniczo musisz zmaterializować listę, aby uzyskać tę wartość.

 2
Author: JP Alioto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-12 15:41:50

Wynik liczby mnogiej.Funkcja Count() może być błędna. Jest to bardzo prosta próbka do przetestowania:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;

namespace Test
{
  class Program
  {
    static void Main(string[] args)
    {
      var test = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };
      var result = test.Split(7);
      int cnt = 0;

      foreach (IEnumerable<int> chunk in result)
      {
        cnt = chunk.Count();
        Console.WriteLine(cnt);
      }
      cnt = result.Count();
      Console.WriteLine(cnt);
      Console.ReadLine();
    }
  }

  static class LinqExt
  {
    public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int chunkLength)
    {
      if (chunkLength <= 0)
        throw new ArgumentOutOfRangeException("chunkLength", "chunkLength must be greater than 0");

      IEnumerable<T> result = null;
      using (IEnumerator<T> enumerator = source.GetEnumerator())
      {
        while (enumerator.MoveNext())
        {
          result = GetChunk(enumerator, chunkLength);
          yield return result;
        }
      }
    }

    static IEnumerable<T> GetChunk<T>(IEnumerator<T> source, int chunkLength)
    {
      int x = chunkLength;
      do
        yield return source.Current;
      while (--x > 0 && source.MoveNext());
    }
  }
}

Wynik musi być (7,7,3,3), ale rzeczywisty wynik to (7,7,3,17)

 2
Author: Roman Golubin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-12 16:41:30

Jedynym sposobem na szybkie liczenie jest, gdy oryginalna kolekcja ma indekser (jak tablica). Aby stworzyć ogólny kod z minimalnym wymaganiem, możesz użyć IEnumerable, ale jeśli potrzebujesz również liczby, moim preferowanym sposobem jest użycie tego interfejsu:


    public interface IEnumAndCount<out T> : IEnumerable<T>
    {
        int Count { get; }
    }

Jeśli oryginalna kolekcja nie ma żadnego indeksatora, implementacja Count może iterować nad kolekcją, ze znanym trafieniem w wydajności O (n).

Jeśli nie chcesz używać czegoś podobnego do / Align = "left" / LinearPolicz z powodów podanych przez Daniela Earwickera na początku tego pytania.

Powodzenia !
 1
Author: Eric Ouellet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-10 17:39:53

Nie.

Czy widzisz, że informacje są dostępne w kodzie, który napisałeś?

Można by argumentować, że kompilator "widzi", że są tylko dwa, ale oznaczałoby to, że musiałby analizować każdą metodę iteratora szukając tylko tego konkretnego patologicznego przypadku. A nawet gdyby tak było, jak byś to przeczytał, biorąc pod uwagę granice liczby mnogiej?

 0
Author: James Curran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-03 21:10:41

Proponuję zadzwonić do Tolista. Tak, robisz wyliczenie wcześniej, ale nadal masz dostęp do listy pozycji.

 0
Author: Jonathan Allen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-04 05:00:20

Może nie daje to najlepszej wydajności, ale możesz użyć LINQ, aby policzyć elementy w liczbie mnogiej:

public int GetEnumerableCount(IEnumerable Enumerable)
{
    return (from object Item in Enumerable
            select Item).Count();
}
 0
Author: Hugo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-26 08:39:09

Używam IEnum<string>.ToArray<string>().Length i działa dobrze.

 -2
Author: Oliver Kötter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-18 09:58:00

Używam takiego kodu, jeśli mam listę ciągów:

((IList<string>)Table).Count
 -2
Author: Me Hungry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-07 10:27:49