Linq Performance: (ElementAt,Count) vs (foreach)
The ElementAt()
method is O(n), unless the actual concrete class that the IEnumerable
represents optimizes it. That means that every time you call it, it has to loop through the entire Enumerable to find the element at n
. Not to mention that since you have i < result.Count()
in the condition part of your for
loop, it's gotta loop through the entire enumerable every single time to get that count.
The second way, you loop through result
exactly once.
Is there a way to access an iteration-counter in Java's for-each loop?
No, but you can provide your own counter.
The reason for this is that the for-each loop internally does not have a counter; it is based on the Iterable interface, i.e. it uses an Iterator
to loop through the "collection" - which may not be a collection at all, and may in fact be something not at all based on indexes (such as a linked list).
Why does Enumerable.Single() iterate all elements, even when more than one item has already been found?
You didn't seem to be the only one thinking that. The .NET Core implementation has an optimized version:
using (IEnumerator<TSource> e = source.GetEnumerator())
{
while (e.MoveNext())
{
TSource result = e.Current;
if (predicate(result))
{
while (e.MoveNext())
{
if (predicate(e.Current))
{
throw Error.MoreThanOneMatch();
}
}
return result;
}
}
}
So to answer your question: there doesn't seem to be a 'good' reason, other than just a developer not thinking about optimizing this use case.
Count the items from a IEnumerableT 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 do you get the index of the current iteration of a foreach loop?
The foreach
is for iterating over collections that implement IEnumerable
. It does this by calling GetEnumerator
on the collection, which will return an Enumerator
.
This Enumerator has a method and a property:
MoveNext()
Current
Current
returns the object that Enumerator is currently on, MoveNext
updates Current
to the next object.
The concept of an index is foreign to the concept of enumeration, and cannot be done.
Because of that, most collections are able to be traversed using an indexer and the for loop construct.
I greatly prefer using a for loop in this situation compared to tracking the index with a local variable.
Foreach loop doesn't iterate over entire IEnumerable
An IEnumerable is an iterator, so it returns one result at a time.
Each time foreach loops, it asks the iterator for the next result. Sometimes results can disappear from the collection being enumerated, so you get unexpected behaviour.
To avoid this, make sure you have all the results before starting the foreach, by calling .ToList()
// Make a list of all documents
List<Document> documentsToAdd;
documentsToAdd = dbEvent.Documents
.Where(dbd => !eventToSave.Documents
.Select(d => d.DocumentId)
.Contains(dbd.DocumentId))
.ToList(); // load all results
// Now this will loop through the whole list
foreach (Document documentToAdd in documentsToAdd)
{
documentToAdd.DocumentType = null;
documentToAdd.DeletedByUser = null;
documentToAdd.DocumentOwnerTeam = null;
documentToAdd.UploadedByUser = null;
documentToAdd.UploadedInStage = null;
hcDbContext.Documents.Add(documentToAdd);
}
How to iterate a loop every n items
You can also do this with LINQ:
var largeList = new List<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
for (int i = 0; i < largeList.Count; i += 3)
{
var items = largeList.Skip(i).Take(3).ToList();
// do stuff with your 3 (or less items)
}
Enumerator consisting of a repeating (but changing) array
Try this one
enum = Enumerator.new do |y|
lap = 1
ss = %w(Start Peak Finish).cycle
loop do
3.times { y << "#{ss.next} Lap #{lap}" }
lap += 1
end
end
enum.first(7)
=> ["Start Lap 1", "Peak Lap 1", "Finish Lap 1", "Start Lap 2", "Peak Lap 2", "Finish Lap 2", "Start Lap 3"]
Related Topics
Rails Syntax Error: Unexpected Keyword_Ensure, Expecting Keyword_End
Why Do I Get "Undefined Method 'Paginate'" Error in Production
Why Non-Explicit Splat Param Plus Default Param Is Wrong Syntax for Method Definition in Ruby 1.9
Getting Rails to Accept European Date Format (Dd/Mm/Yyyy)
Algorithm to Shuffle an Array Randomly Based on Different Weights
Chrome Asks to "Select a Certificate" for Ssl on My Rails App Using Thin
Rails Not Working for New Project. Showingerror " Superclass Mismatch for Class Cipher (Typeerror)"
Why Does Ruby '**' Operator Have Higher Precedence Than Unary '-'
How to Call a JavaScript Function from an HTML.Erb
Jekyll:New Posts Not Being Generated
Ruby Sequel: Array Returned by Query Is Being Returned as a String Object, Not an Array Object
Pass Arguments by Reference to a Block with the Splat Operator
Idiomatically Mock Openuri.Open_Uri with Minitest
Validating Phone Number in Ruby