Count the items from a IEnumerable T without iterating?
IEnumerable
doesn't support this. This is by design. IEnumerable
uses lazy evaluation to get the elements you ask for just before you need them.
If you want to know the number of items without iterating over them you can use ICollection<T>
, it has a Count
property.
How should I get the length of an IEnumerable?
If you need to read the number of items in an IEnumerable<T>
you have to call the extension method Count
, which in general (look at Matthew comment) would internally iterate through the elements of the sequence and it will return you the number of items in the sequence. There isn't any other more immediate way.
If you know that your sequence is an array, you could cast it and read the number of items using the Length
property.
No, in later versions there isn't any such method.
For implementation details of Count
method, please have a look at here.
The best way to get a count of IEnumerable T
You will have to enumerate to get a count. Other constructs like the List keep a running count.
IEnumerable T .Count() returns 0
Thank you for clarifying that you were filtering the list after materializing it in the Get()
method.
Your issue is that LINQ is a view. So if you iterate an IEnumerable
twice, it will go through the source items twice, applying any filters, projections, etc. to the source items. This means that by changing the source items, the enumerable will yield different items the second time you iterate through it because those items no longer match the filter.
I would suggest you modify the method to be like this:
private async Task<int> ApproveOrRejectWorkItems(IEnumerable<WorkItem> workItems, int status)
{
var workItemsToBeUpdated = workItems.Count();
foreach (var workItem in workItems.Where(it => it.StatusId == (int)WorkItemStatus.Submitted))
{
workItem.StatusId = status;
}
await _unitOfWork.WorkItemRepository.Update(workItems);
return workItems.Count();
}
Performance of Enumerable Count method in a loop
Calling Count()
on an enumerable source will exhaust the enumerable until all elements are enumerated. Calling Count()
on an enumerable in the condition-block in a for loop will therefore exhaust the enumerable at every iteration. For example, calling
var numbers = VerboseRange(1, 5);
for (var index = 0; index < numbers.Count(); index++)
{
Console.WriteLine($"For-loop is at index {index}...");
}
IEnumerable<int> VerboseRange(int start, int count)
{
foreach (var number in Enumerable.Range(start, count))
{
Console.WriteLine($"Yielded number {number}.");
yield return number;
}
}
will output
Yielded number 1.
Yielded number 2.
Yielded number 3.
Yielded number 4.
Yielded number 5.
For-loop is at index 0...
Yielded number 1.
Yielded number 2.
Yielded number 3.
Yielded number 4.
Yielded number 5.
For-loop is at index 1...
Yielded number 1.
Yielded number 2.
Yielded number 3.
Yielded number 4.
Yielded number 5.
For-loop is at index 2...
Yielded number 1.
Yielded number 2.
Yielded number 3.
Yielded number 4.
Yielded number 5.
For-loop is at index 3...
Yielded number 1.
Yielded number 2.
Yielded number 3.
Yielded number 4.
Yielded number 5.
For-loop is at index 4...
Yielded number 1.
Yielded number 2.
Yielded number 3.
Yielded number 4.
Yielded number 5.
Therefore, counting before is better.
However, I would recommend you to use a counter and a foreach
-loop
var count = 0;
foreach (var item in items)
{
// do something
count++;
}
In C# 7.0, you can finally do
foreach (var (item, index) in items.WithIndex())
{
// do something
}
Performance of IEnumerable T .Count() - difference between iterating over value types and reference types
myEnumerable.Count();
replaced with this:
myEnumerable.Select(el => el.Id).Count();
That definitely fall performance! I don't know how you compare these that conclude it's better but you can easily compare them as follows:
class TestObj
{
public int Id { get; set; }
}
static void Main(string[] args)
{
var dataRef = Enumerable.Empty<TestObj>();
for (int i = 0; i < 100000; i++)
{
dataRef = dataRef.Append(new TestObj { Id = i });
}
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 100000; i++)
{
dataRef.Count();
}
sw.Stop();
Console.WriteLine($"By Ref: {sw.ElapsedMilliseconds / 1000.0} Sec");
sw.Restart();
var dataVal = dataRef.Select(p => p.Id);
for (int i = 0; i < 100000; i++)
{
dataVal.Count();
}
Console.WriteLine($"By Val: {sw.ElapsedMilliseconds / 1000.0} Sec");
}
Results:
By Ref: 0.002 Sec
By Val: 4.111 Sec
Generally ValueType
and ReferenceType
if we consider them independently as two enumerable, don't have any significant different in iterating time and counting.
But what you did above is adding addition enumeration on reference type enumerable to convert it to value type enumerable and that leads to many overhead and degregation of performance.
If performance is your concern and you're ready to pay its cost by memory, you can use .ToList()
and then .Count()
will takes near to zero.
How can I count the number of elements in IEnumerator?
Directory.GetFiles(@"C:\yourdir").Length
will give you count directly
Related Topics
Right Click Context Menu for Datagridview
Insert Entire Datatable into Database at Once Instead of Row by Row
C#: Class for Decoding Quoted-Printable Encoding
Css, Images, Js Not Loading in Iis
How to Change the Color of Progressbar in C# .Net 3.5
Exclude Property from Serialization via Custom Attribute (JSON.Net)
Mvc3 Razor Dropdownlistfor Enums
Regular Expression to Split on Spaces Unless in Quotes
How to Force All Referenced Assemblies to Be Loaded into the App Domain
Getting File Names Without Extensions
"On Exit" for a Console Application