Counter variable in foreach loop #1584
Replies: 46 comments 4 replies
-
As a more general solution, I'd prefer to see the For-Each solution support blocks in its regions.
|
Beta Was this translation helpful? Give feedback.
-
This is some code that I use too:
|
Beta Was this translation helpful? Give feedback.
-
https://gist.github.com/ufcpp/2b3e1a5821169f6b21ded175ad05c752#file-program-cs-L25 |
Beta Was this translation helpful? Give feedback.
-
I think that a tuple-based |
Beta Was this translation helpful? Give feedback.
-
Why not use
|
Beta Was this translation helpful? Give feedback.
-
@ethanae |
Beta Was this translation helpful? Give feedback.
-
I call mine |
Beta Was this translation helpful? Give feedback.
-
@TonyValenti Your |
Beta Was this translation helpful? Give feedback.
-
@jnm2, As @svick says, it would be good to have the core libraries add this to |
Beta Was this translation helpful? Give feedback.
-
Counter proposal: foreach (var item in items; in int counter)
{
Console.WriteLine(counter);
Console.WriteLine(item);
} This would allow the user to access the counter, but not actually effect it. If they want to manipulate the counter, they should really just use a
|
Beta Was this translation helpful? Give feedback.
-
That's confusing, since Also, the iteration variable of a |
Beta Was this translation helpful? Give feedback.
-
Another counter counter-proposal: 😛 foreach (var item[index] in items)
{
Console.WriteLine(index);
} (Edited, we shouldn't be incrementing, that can be handled automatically.) |
Beta Was this translation helpful? Give feedback.
-
I agree that The difference between them as I would interpret it on first glance is: The difference between the latter two won't be important in most cases, but could be important in some. Edit: I suppose as an alternative, it could be up to the user to decide which they want for their use case. |
Beta Was this translation helpful? Give feedback.
-
I liked the in proposal but i thought it should have been an out var.
On Fri, Jun 1, 2018 at 6:10 PM Unlocked ***@***.***> wrote:
I agree that in was probably not the best choice. However, if it's just int
counter without any modifier, my concern is that there would be an
implication that it's just like any other variable, which wouldn't be true.
Requiring readonly or in would get the message across, though as you
pointed out, in could be confusing.
The difference between them as I would interpret it on first glance is:
Nothing: Isn't readonly; same variable for the entire loop
in: Readonly; same variable for the entire loop
readonly: Readonly; different variable for each iteration
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<https://github.com/dotnet/csharplang/issues/1584#issuecomment-394032337>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AM-qVpH-qxxOZwGYc5WO5Yq9OPUHqiMGks5t4cnmgaJpZM4UUvCj>
.
--
Always glad to help,
[image: AlphaDrive for Clio] <https://www.alphadriveforclio.com/>
Tony Valenti
Software Engineer
T: 402-401-7568 <javascript:void(0);>
E: [email protected]
W: www.AlphaDriveForClio.com <https://www.alphadriveforclio.com/>
Schedule a Meeting with Me
<https://www.alphadriveforclio.com/schedule-meeting>
This message contains confidential information and is intended only for the
intended recipients. If you are not an intended recipient you should not
disseminate, distribute or copy this e-mail. Please notify us immediately
by e-mail if you have received this e-mail by mistake and delete this
e-mail from your system. E-mail transmission cannot be guaranteed to be
secure or error-free as information could be intercepted, corrupted, lost,
destroyed, arrive late or incomplete, or contain viruses. Therefore we do
not accept liability for any errors or omissions in the contents of this
message, which arise as a result of e-mail transmission. If verification is
required please request a hard-copy version.
|
Beta Was this translation helpful? Give feedback.
-
One line of reply, 44 lines of email boilerplate. 😄 |
Beta Was this translation helpful? Give feedback.
-
Other languages have this useful feature: for index, element := range someSlice {
// index is the index where we are
// element is the element from someSlice for where we are
} Swift: for (index, element) in list.enumerated() {
print("Item \(index): \(element)")
} D: foreach (i, e; [4, 5, 6]) {
writeln(i, ":", e);
}
// 0:4 1:5 2:6 They all put the indexer before the variable which I find weird. I like this syntax best: foreach(var item @ index in collection ) {
...
} The extension methods on IE have negative performance characteristics just for one indexer. I think this should be a standard language feature. |
Beta Was this translation helpful? Give feedback.
-
Why is that the case? If you have: public struct IndexedEnumerable<T>
{
private readonly IEnumerable<T> values;
public IndexedEnumerable(IEnumerable<T> values)
=> this.values = values;
public Enumerator GetEnumerator()
=> new Enumerator(values.GetEnumerator());
public struct Enumerator
{
private readonly IEnumerator<T> enumerator;
public int index;
public Enumerator(IEnumerator<T> enumerator)
{
this.enumerator = enumerator;
index = -1;
}
public bool MoveNext()
{
index++;
return enumerator.MoveNext();
}
public (int, T) Current => (index, enumerator.Current);
}
}
public static class Enumerable
{
public static IndexedEnumerable<T> Indexed<T>(this IEnumerable<T> values)
=> new IndexedEnumerable<T>(values);
}
class Test
{
static void Main(string[] args)
{
foreach (var (index, val) in args.Indexed())
{
}
}
} Then that should be pretty darn fast. There are no actual allocations going on here. -- For those concerned about what happens if you have an existing struct-enumerator to work with, then Shapes helps solve that becuase you'd write the above with SEnumerable and SEnumerator instead, giving you a shape-based way to do this with almost no perf overhead. So, in other words, i don't think we actually need this proposal, because it can be done today already with existing langauge features (or subsumed into other upcoming language features). |
Beta Was this translation helpful? Give feedback.
-
That makes sense to me. If i iterate a dictionary, i get Key-Values, not Value-Keys. For a sequence, the key is the index. So i get Index-Value, not Value-Index. |
Beta Was this translation helpful? Give feedback.
-
Note: if we ever get struct-enumeration in the language, tehn the above could just be written as: public static class Enumerable
{
public static struct IndexedEnumerable<T> Indexed<T>(this IEnumerable<T> values)
{
int index = 0;
foreach (var val in values)
{
yield return (index++, val);
}
} But until then, manually writing it out is the way to go. |
Beta Was this translation helpful? Give feedback.
-
I get the logic. I guess it makes more sense when
I agree. But my understanding is with simple collections such as lists and arrays the compiler makes optimizations to not threat them through an IE interface, instead iterates over them like in a for loop, where foreach becomes only syntactic sugar. In this case such optimization cannot be made. |
Beta Was this translation helpful? Give feedback.
-
I mentioned this bit:
|
Beta Was this translation helpful? Give feedback.
-
Throwing my hat into the ring for a syntax suggestion:
|
Beta Was this translation helpful? Give feedback.
-
Issue #3194 would enhance they way foreach looks for an implementation pattern, in the same way that asyc and deconstruction is already pattern based. If that lands in C#, a simple extension method would make iteration with an index trivial, no other new syntax for C# required. First, write a suitable extension method: public static IEnumerator<(T, int)> GetEnumerator<T>(this IEnumerable<T> items)
{
int index = 0;
foreach(var i in items)
{
yield return (i, index++);
}
} and then you can iterate over any sequence using a tuple: foreach ( var (Person, int) in FindPeople()) { ... } or, perhaps preferably, foreach ((Person p, int i) in FindPeople()) { ... } An independent enhancement to the compiler to make the implementation of |
Beta Was this translation helpful? Give feedback.
-
Fwiw @YairHalberstadt has an implementation pr out that is in the process of being reviewed, and if everything goes nicely I hope it'll be in 9. No guarantees, but that's my hope. |
Beta Was this translation helpful? Give feedback.
-
@theunrepentantgeek I don't think that will work, since to preserve backwards compatibility IEnumerable is preferred over an extension GetEnumerator, and besides it is not target typed. |
Beta Was this translation helpful? Give feedback.
-
That's a shame. When I skimmed through #3194, I thought it would fall back to the extension Apologies for misreading it. |
Beta Was this translation helpful? Give feedback.
-
How about this slightly modified version of the original proposal? foreach (Foo foo in foos; index) // `index` is implicitly a read-only `int`. Allow custom name for the case of nested loops, and for consistency with `for`.
{
Console.WriteLine($"[{index}] {foo}");
}
// Translates to:
using (IEnumerator<Foo> enumerator = foos.GetEnumerator())
{
int index = 0;
while (enumerator.MoveNext())
{
Foo foo = enumerator.Current;
Console.WriteLine($"[{index}] {foo}");
index++;
}
} |
Beta Was this translation helpful? Give feedback.
-
What would it take to add the tuple foreach syntax into the language itself instead of having to rely on an extension method? Extension method example from above: foreach (var (item, index) in collection.Indexed())
{
DoSomething(item, index);
} Proposal: foreach (var (item, index) in collection)
{
DoSomething(item, index);
} I'd like the language itself to contextually return I think this approach is most consistent with current C# functionality because it's the same syntax used in |
Beta Was this translation helpful? Give feedback.
-
Another benefit of using extension method over syntax is you can chain it with linq and clearly understand what it is // suppose there is Select that return (item,index)
foreach(var ((item,i),count) in list.Select().Where((pair) => pair.item.IsWhatIWant).Select())
{
// i is original index in the list
// count is number of filtered/sorted
} |
Beta Was this translation helpful? Give feedback.
-
I think we should do the change on for loop rather then foreach loop because not all IEnumerator interface implementations implements .Item[Index] as member (say, Hashtable or most key-based collections) And for collections like Tree which we can have multiple transversal methods (and typically implements IEnumerator), index doesn't really have meaning there. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
A feature to define counter variable in
foreach
loop, something like:currently we can use following way:
Beta Was this translation helpful? Give feedback.
All reactions