นับรายการจาก IE ที่นับได้โดยไม่ต้องวนซ้ำ?


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

สมมติว่าฉันต้องการทำซ้ำในสิ่งเหล่านั้นและเขียนสิ่งที่ต้องการประมวลผล #n ของ #m

มีวิธีที่ฉันสามารถหาค่าของ m โดยไม่ต้องทำซ้ำก่อนการทำซ้ำหลักของฉันหรือไม่?

ฉันหวังว่าฉันทำให้ตัวเองชัดเจน

คำตอบ:


338

IEnumerableไม่รองรับสิ่งนี้ นี่คือโดยการออกแบบ IEnumerableใช้การประเมินแบบขี้เกียจเพื่อให้ได้องค์ประกอบที่คุณต้องการก่อนที่คุณจะต้องการ

หากคุณต้องการทราบจำนวนรายการโดยไม่ต้องวนซ้ำพวกเขาคุณสามารถใช้ICollection<T>มันมีCountคุณสมบัติ


38
ฉันชอบ ICollection มากกว่า IList ถ้าคุณไม่จำเป็นต้องเข้าถึงรายการด้วยตัวสร้างดัชนี
Michael Meadows

3
ฉันมักจะคว้า List และ IList ออกจากนิสัย แต่โดยเฉพาะถ้าคุณต้องการที่จะใช้พวกเขาด้วยตัวเอง ICollection นั้นง่ายกว่าและมีคุณสมบัติ Count ขอบคุณ!
Mendelt

21
@Shimmy คุณย้ำและนับองค์ประกอบ หรือคุณเรียกใช้ Count () จากเนมสเปซ Linq ที่ทำเพื่อคุณ
Mendelt

1
ควรเปลี่ยน IEnumerable ด้วย IList ให้เพียงพอภายใต้สถานการณ์ปกติหรือไม่?
Teekin

1
@Helgi เนื่องจาก IEnumerable ถูกประเมินอย่างขี้เกียจคุณสามารถใช้กับสิ่งที่ IList ไม่สามารถใช้ได้ คุณสามารถสร้างฟังก์ชั่นที่คืนค่า IEnumerable ที่แจกแจงทศนิยมทั้งหมดของ Pi เช่น ตราบใดที่คุณไม่เคยพยายามทำนายผลที่สมบูรณ์มันก็ควรจะได้ผล คุณไม่สามารถสร้าง IList ที่มี Pi แต่นั่นคือทั้งหมดวิชาการสวย สำหรับการใช้งานทั่วไปฉันเห็นด้วยอย่างยิ่ง หากคุณต้องการนับคุณต้อง IList :-)
Mendelt

215

System.Linq.Enumerable.CountวิธีขยายบนIEnumerable<T>มีการดำเนินการดังต่อไปนี้:

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;

ดังนั้นจึงพยายามที่จะส่งICollection<T>ซึ่งมีCountทรัพย์สินและใช้มันหากเป็นไปได้ มิฉะนั้นจะวนซ้ำ

ดังนั้นทางออกที่ดีที่สุดของคุณคือการใช้Count()วิธีการขยายบนIEnumerable<T>วัตถุของคุณเนื่องจากคุณจะได้รับประสิทธิภาพที่ดีที่สุดเท่าที่จะเป็นไปได้


13
สิ่งที่น่าสนใจมาก ๆ มันพยายามที่จะโยนไปICollection<T>ก่อน
Oscar Mederos

1
@OscarMederos ส่วนใหญ่ของวิธีการขยายใน Enumerable มีการปรับแต่งสำหรับลำดับของประเภทต่างๆที่พวกเขาจะใช้วิธีที่ถูกกว่าถ้าพวกเขาสามารถ
Shibumi

1
ส่วนขยายที่กล่าวถึงมีตั้งแต่สุทธิ 3.5 และเอกสารในMSDN
คริสเตียน

ฉันคิดว่าคุณไม่จำเป็นต้องประเภททั่วไปTบนIEnumerator<T> enumerator = source.GetEnumerator()เพียงแค่คุณสามารถทำสิ่งนี้IEnumerator enumerator = source.GetEnumerator()และควรทำงาน!
Jaider

7
@Jaider - มันซับซ้อนกว่านั้นเล็กน้อย IEnumerable<T>สืบทอดIDisposableซึ่งอนุญาตให้usingคำสั่งกำจัดโดยอัตโนมัติ IEnumerableไม่. ดังนั้นหากคุณโทรGetEnumeratorทางใดทางหนึ่งคุณควรจบด้วยvar d = e as IDisposable; if (d != null) d.Dispose();
Daniel Earwicker

87

เพียงเพิ่มข้อมูลพิเศษ:

Count()นามสกุลไม่เคยย้ำ พิจารณา Linq ถึง Sql โดยที่การนับไปที่ฐานข้อมูล แต่แทนที่จะนำแถวกลับมาทั้งหมดมันจะออกCount()คำสั่งSql และส่งกลับผลลัพธ์นั้นแทน

นอกจากนี้คอมไพเลอร์ (หรือรันไทม์) นั้นฉลาดพอที่จะเรียกใช้Count()เมธอดobject ถ้ามี ดังนั้นจึงไม่เหมือนที่ผู้เผชิญเหตุคนอื่นพูดว่าไม่รู้อย่างสมบูรณ์และวนซ้ำเสมอเพื่อนับองค์ประกอบ

ในหลายกรณีที่โปรแกรมเมอร์กำลังตรวจสอบif( enumerable.Count != 0 )โดยใช้Any()วิธีการขยายเนื่องจากif( enumerable.Any() ) มีประสิทธิภาพมากกว่าด้วยการประเมินที่ขี้เกียจของ linq เนื่องจากสามารถลัดวงจรเมื่อสามารถตรวจสอบได้ว่ามีองค์ประกอบใดบ้าง นอกจากนี้ยังสามารถอ่านได้มากขึ้น


2
เกี่ยวกับคอลเลกชันและอาร์เรย์ หากคุณบังเอิญใช้คอลเลกชันให้ใช้.Countคุณสมบัติตามที่มันรู้ขนาดของมันเสมอ เมื่อทำการสืบค้นcollection.Countไม่มีการคำนวณเพิ่มเติมมันก็จะส่งกลับจำนวนที่รู้จักกันอยู่แล้ว เช่นเดียวArray.lengthกับที่ฉันรู้ แต่.Any()ได้รับการแจงนับของแหล่งที่ใช้และผลตอบแทนจริงถ้ามันสามารถทำusing (IEnumerator<TSource> enumerator = source.GetEnumerator()) enumerator.MoveNext()สำหรับคอลเลกชัน: if(collection.Count > 0)อาร์เรย์: if(array.length > 0)และ enumerables if(collection.Any())ทำ
Nope

1
จุดแรกที่ไม่เป็นความจริงอย่างเคร่งครัด ... LINQ กับ SQL ใช้วิธีขยายนี้ซึ่งไม่ได้เช่นเดียวกับคนนี้ หากคุณใช้ที่สองการนับจะถูกดำเนินการในหน่วยความจำไม่ใช่ฟังก์ชัน SQL
AlexFoxGill

1
@AlexFoxGill ถูกต้อง หากคุณส่งIQueryably<T>ไปที่ a อย่างชัดเจนIEnumerable<T>จะไม่มีการนับจำนวน sql เมื่อฉันเขียนสิ่งนี้ Linq ถึง Sql เป็นสิ่งใหม่ ฉันคิดว่าฉันแค่ผลักดันให้ใช้Any()เพราะสำหรับ enumerables คอลเลกชันและ sql มันมีประสิทธิภาพมากขึ้นและสามารถอ่านได้ (โดยทั่วไป) ขอบคุณสำหรับการปรับปรุงคำตอบ
Robert Paulson

12

เพื่อนของฉันมีชุดบทความบล็อกที่แสดงภาพประกอบว่าทำไมคุณถึงทำไม่ได้ เขาสร้างฟังก์ชั่นที่คืนค่า IEnumerable โดยที่การวนซ้ำแต่ละครั้งส่งคืนหมายเลขเฉพาะถัดไปตลอดทางจนถึงulong.MaxValueและรายการถัดไปจะไม่ถูกคำนวณจนกว่าคุณจะขอ คำถามป๊อปอัพอย่างรวดเร็ว: มีรายการกี่รายการที่ส่งคืน

นี่คือโพสต์ แต่มันยาว:

  1. Beyond Loops (จัดเตรียมคลาส EnumerableUtility เริ่มต้นที่ใช้ในโพสต์อื่น ๆ )
  2. แอพพลิเคชั่นของ Iterate (การติดตั้งครั้งแรก)
  3. วิธีการ Extention บ้า: ToLazyList (การเพิ่มประสิทธิภาพประสิทธิภาพ)

2
ฉันอยากให้ MS กำหนดวิธีที่จะขอให้คนนับจำนวนอธิบายถึงสิ่งที่พวกเขาสามารถทำได้ด้วยตัวเอง (โดยที่ "ไม่รู้อะไรเลย" เป็นคำตอบที่ถูกต้อง) ไม่ต้องนับจำนวนที่มีปัญหาในการตอบคำถามเช่น "คุณรู้ว่าตัวเองมีขอบเขต", "คุณรู้ไหมว่าตัวเองมีขอบเขตน้อยกว่าองค์ประกอบ N" และ "คุณรู้ว่าตัวเองไม่มีที่สิ้นสุด" เนื่องจากการนับจำนวนใด ๆ (ถ้าไม่ช่วยเหลือ) ตอบ "ไม่" กับทุกคน ถ้ามีวิธีมาตรฐานสำหรับการถามคำถามดังกล่าวก็จะมีความปลอดภัยมากสำหรับ enumerators จะกลับมาวนเวียนไม่รู้จบ ...
SuperCat

1
... (เนื่องจากพวกเขาสามารถพูดได้ว่าพวกเขาทำเช่นนั้น) และสำหรับรหัสที่จะสมมติว่าตัวแจงนับที่ไม่ได้อ้างว่าส่งคืนลำดับที่ไม่มีที่สิ้นสุดมีแนวโน้มที่จะถูก จำกัด ขอบเขต โปรดทราบว่าการรวมวิธีการถามคำถามดังกล่าว (เพื่อลดสำเร็จรูปให้คงอาจมีทรัพย์สินส่งคืนEnumerableFeaturesวัตถุ) จะไม่ต้องการให้ enumerators ทำอะไรยาก แต่ความสามารถในการถามคำถามดังกล่าว (พร้อมกับคนอื่น ๆ เช่น "คุณสามารถสัญญา กลับรายการในลำดับเดิมเสมอ "," คุณสามารถเปิดเผยรหัสที่ไม่ควรเปลี่ยนชุดสะสมของคุณได้อย่างปลอดภัย "ฯลฯ ) จะมีประโยชน์มาก
supercat

นั่นจะค่อนข้างเจ๋ง แต่ตอนนี้ฉันแน่ใจแล้วว่ามันจะเข้ากันได้ดีกับบล็อกตัววนซ้ำ คุณต้องการบางอย่าง "ตัวเลือกผลตอบแทน" พิเศษหรือบางอย่าง หรืออาจจะใช้คุณลักษณะเพื่อตกแต่งวิธีการวนซ้ำ
Joel Coehoorn

1
ในกรณีที่ไม่มีการประกาศพิเศษอื่น ๆ เพียงแค่รายงานว่าพวกเขาไม่รู้อะไรเลยเกี่ยวกับลำดับที่ส่งคืนแม้ว่า IEnumerator หรือผู้สืบทอด MS ที่ลงนามรับรอง (ซึ่งสามารถส่งคืนโดยการใช้งาน GetEnumerator ที่รู้ถึงการมีอยู่) เพื่อสนับสนุนข้อมูลเพิ่มเติม C # มีแนวโน้มที่จะได้รับset yield optionsข้อความหรือสิ่งที่คล้ายกันเพื่อสนับสนุน หากได้รับการออกแบบอย่างเหมาะสมIEnhancedEnumeratorสิ่งที่สามารถทำให้ LINQ สามารถใช้งานได้มากขึ้นโดยการกำจัด "การป้องกัน" ToArrayหรือการToListโทรจำนวนมากโดยเฉพาะอย่างยิ่ง ...
supercat

... ในกรณีที่สิ่งต่าง ๆEnumerable.Concatถูกนำมาใช้เพื่อรวมชุดใหญ่ที่รู้มากเกี่ยวกับตัวเองกับชุดเล็ก ๆ ที่ไม่ได้
supercat

10

IEnumerable ไม่สามารถนับได้หากไม่วนซ้ำ

ภายใต้สถานการณ์ "ปกติ" อาจเป็นไปได้สำหรับคลาสที่ใช้ IEnumerable หรือ IEnumerable <T> เช่น List <T> เพื่อใช้เมธอด Count โดยส่งกลับคุณสมบัติ List <T> .Count อย่างไรก็ตามวิธีการนับนั้นไม่ใช่วิธีที่กำหนดไว้ใน IEnumerable <T> หรืออินเทอร์เฟซ IEnumerable (อันที่จริงอันเดียวคือในความเป็นจริงคือ GetEnumerator) และนี่หมายความว่าไม่สามารถให้การใช้งานเฉพาะคลาสได้

ค่อนข้างนับเป็นวิธีการขยายที่กำหนดไว้ในคลาสคงที่ Enumerable ซึ่งหมายความว่าสามารถเรียกใช้บนอินสแตนซ์ใด ๆ ของคลาสที่ได้รับมา IEnumerable <T> โดยไม่คำนึงถึงการใช้งานของคลาสนั้น แต่มันก็หมายความว่ามันจะถูกนำไปใช้ในสถานที่เดียวภายนอกใด ๆ ของชั้นเรียนเหล่านั้น ซึ่งแน่นอนหมายความว่าจะต้องมีการดำเนินการในลักษณะที่เป็นอิสระจากการฝึกงานของคลาสเหล่านี้ วิธีเดียวที่จะทำการนับคือผ่านการวนซ้ำ


เป็นจุดที่ดีที่คุณไม่สามารถนับได้เว้นแต่คุณจะทำซ้ำ ฟังก์ชันการนับจะเชื่อมโยงกับคลาสที่ใช้ IEnumerable .... ดังนั้นคุณต้องตรวจสอบว่า IEnumerable ประเภทใดที่เข้ามา (ตรวจสอบโดยการส่ง) แล้วคุณจะรู้ว่า List <> และ Dictionary <> มีวิธีที่แน่นอนในการนับและใช้ สิ่งเหล่านั้นหลังจากที่คุณรู้ว่าประเภท ฉันพบว่าหัวข้อนี้มีประโยชน์มากโดยส่วนตัวดังนั้นขอขอบคุณสำหรับคำตอบของคุณเช่นกัน Chris
PositiveGuy

1
ตามคำตอบของ Daniel คำตอบนี้ไม่เป็นความจริงอย่างเด็ดขาด: การนำไปใช้ตรวจสอบว่าวัตถุนั้นใช้ "ICollection" ซึ่งมีฟิลด์ "Count" หรือไม่ ถ้าเป็นเช่นนั้นจะใช้มัน (ไม่ว่ามันจะฉลาดขนาดนั้นใน '08 ฉันไม่รู้)
ToolmakerSteve


8

ไม่ไม่โดยทั่วไป จุดหนึ่งในการใช้ enumerables คือไม่ทราบชุดของวัตถุที่แท้จริงในการแจงนับ (ล่วงหน้าหรือแม้แต่ทั้งหมด)


จุดสำคัญที่คุณนำมาใช้คือแม้ว่าคุณจะได้รับวัตถุ IEnumerable นั้นคุณต้องดูว่าคุณสามารถใช้มันเพื่อหาว่ามันเป็นประเภทใด นั่นเป็นจุดที่สำคัญมากสำหรับผู้ที่พยายามใช้ IEnumerable เช่นฉันในรหัสของฉัน
PositiveGuy

8

คุณสามารถใช้ System.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());
    }
}

คุณจะได้ผลลัพธ์ '2'


3
นี้ไม่ได้ทำงานให้กับตัวแปรที่ไม่ใช่ทั่วไป IEnumerable (โดยไม่ระบุชนิด)
มาร์เซล

การดำเนินการของ. Count กำลังแจกแจงไอเท็มทั้งหมดหากคุณมี IEnumerable (แตกต่างกันสำหรับ ICollection) คำถาม OP ชัดเจน "โดยไม่ต้องทำซ้ำ"
JDC

5

จะเกินกว่าคำถามของคุณได้ทันที (ซึ่งได้รับการตอบรับอย่างทั่วถึงในเชิงลบ) หากคุณกำลังมองหาเพื่อรายงานความคืบหน้าในขณะที่การประมวลผลนับคุณอาจต้องการที่จะมองไปที่โพสต์บล็อกของฉันรายงานความคืบหน้าในช่วง Linq แบบสอบถาม

มันช่วยให้คุณทำสิ่งนี้:

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
      };

4

ฉันใช้วิธีดังกล่าวภายในวิธีการตรวจสอบIEnumberableเนื้อหาที่ส่งผ่าน

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

}

ภายในวิธีการเช่นนี้:

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

}

1
ทำไมทำอย่างนั้น? "Count" อาจมีราคาแพงดังนั้นเมื่อกำหนด IEnumerable ให้ถูกต้องเพื่อเริ่มต้นสิ่งที่เอาต์พุตที่คุณต้องการเพื่อให้มีค่าเริ่มต้นที่เหมาะสมจากนั้นเริ่มต้นการทำซ้ำผ่าน "iEnum" เลือกค่าเริ่มต้นเช่น "iEnum" ที่ว่างเปล่าซึ่งไม่ดำเนินการวนซ้ำจบลงด้วยผลลัพธ์ที่ถูกต้อง บางครั้งสิ่งนี้หมายถึงการเพิ่มธงบูลีนเพื่อให้ทราบว่ามีการดำเนินการลูปหรือไม่ จริงอยู่ที่ว่ามันเงอะงะ แต่การใช้ "Count" นั้นดูไม่ฉลาด bool hasContents = false; if (iEnum != null) foreach (object ob in iEnum) { hasContents = true; ... your code per ob ... }หากจำเป็นต้องใช้ธงนี้รหัสดูเหมือนว่า:
ToolmakerSteve

... มันเป็นยังง่ายต่อการเพิ่มรหัสพิเศษที่ควรจะทำเพียงครั้งแรกหรือเฉพาะในการทำซ้ำอื่น ๆกว่าครั้งแรก: ` ... {{ถ้า hasContents = true; (hasContents!) .. รหัสเวลาหนึ่ง .. .. ; } else {..code สำหรับทุกคนยกเว้นครั้งแรก .. } ... } "เป็นที่ยอมรับว่านี่เป็นวิธีที่ง่ายกว่าวิธีการที่ง่ายซึ่งรหัสครั้งเดียวจะอยู่ภายในของคุณถ้าก่อนหน้าลูป แต่ถ้าค่าใช้จ่ายของ" .Count () "อาจเป็นข้อกังวลดังนั้นนี่คือวิธีที่จะไป
ToolmakerSteve

3

ขึ้นอยู่กับ. Net รุ่นใดและการใช้งาน IEnumerable object ของคุณ Microsoft ได้แก้ไขวิธี IEnumerable.Count เพื่อตรวจสอบการใช้งานและใช้ ICollection.Count หรือ ICollection <TSource> .Count ดูรายละเอียดได้ที่นี่https://connect.microsoft.com/VisualStudio/feedback/details/454130

และด้านล่างคือ MSIL จาก Ildasm สำหรับ System.Core ซึ่ง System.Linq ตั้งอยู่

.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


2

ผลลัพธ์ของฟังก์ชัน IEnumerable.Count () อาจผิด นี่เป็นตัวอย่างง่ายๆในการทดสอบ:

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());
    }
  }
}

ผลลัพธ์ต้องเป็น (7,7,3,3) แต่ผลลัพธ์ที่แท้จริงคือ (7,7,3,17)


1

วิธีที่ดีที่สุดที่ฉันพบคือนับด้วยการแปลงเป็นรายการ

IEnumerable<T> enumList = ReturnFromSomeFunction();

int count = new List<T>(enumList).Count;

-1

ฉันขอแนะนำให้โทร ToList ใช่คุณกำลังทำการแจงนับ แต่ยังคงสามารถเข้าถึงรายการของคุณได้


-1

อาจไม่ได้ประสิทธิภาพที่ดีที่สุด แต่คุณสามารถใช้ LINQ เพื่อนับองค์ประกอบใน IEnumerable:

public int GetEnumerableCount(IEnumerable Enumerable)
{
    return (from object Item in Enumerable
            select Item).Count();
}

ผลลัพธ์แตกต่างจากการทำ "` return Enumerable.Count (); "อย่างไร?
ToolmakerSteve

คำถามที่ดีหรือจริง ๆ แล้วมันเป็นคำตอบสำหรับคำถาม Stackoverflow นี้
Hugo

-1

ฉันคิดว่าวิธีที่ง่ายที่สุดในการทำเช่นนี้

Enumerable.Count<TSource>(IEnumerable<TSource> source)

การอ้างอิง: system.linq.enumerable


คำถามคือ "นับรายการจาก IE ที่นับได้ <T> โดยไม่ต้องวนซ้ำ?" คำตอบนี้เป็นอย่างไร
Enigmativity

-3

ฉันใช้IEnum<string>.ToArray<string>().Lengthและใช้งานได้ดี


ควรทำงานได้ดี IEnumerator <object> .ToArray <object> .Length
ดินแดง

1
ทำไมคุณถึงทำเช่นนี้แทนที่จะเป็นวิธีแก้ปัญหาที่กระชับและมีประสิทธิภาพมากกว่าที่ได้ให้ไว้แล้วในคำตอบที่ได้รับการโหวตอย่างสูงของแดเนียลซึ่งเขียนไว้ก่อนหน้านี้เมื่อสามปีก่อน " IEnum<string>.Count();"
ToolmakerSteve

คุณพูดถูก อย่างใดฉันมองข้ามคำตอบของแดเนียลอาจเป็นเพราะเขาอ้างจากการดำเนินการและฉันคิดว่าเขาใช้วิธีการขยายและฉันกำลังมองหาวิธีการแก้ปัญหาด้วยรหัสน้อย
Oliver Kötter

วิธีที่ได้รับการยอมรับมากที่สุดในการจัดการคำตอบที่ไม่ดีของฉันคืออะไร ฉันควรลบหรือไม่
Oliver Kötter

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.