Thread overview | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
September 21, 2015 foreach automoatic counter? | ||||
---|---|---|---|---|
| ||||
Going through a book on coding in D, http://ddili.org/ders/d.en/foreach.html , I find the following very useful feature: When two names are specified in the names section [with a plain array], they represent an automatic counter and the value of the element, respectively: foreach (i, element; array) { writeln(i, ": ", element); } I understand that foreach is built on top of a for loop... I'm just wondering why I can't access the automatic counter from a doubly linked list, or an associative array, or some range? It's pretty common for me to have to rewrite foreach loops to be for loops when I get to the bottom and realize I need to know where in the sequence I am... |
September 21, 2015 Re: foreach automoatic counter? | ||||
---|---|---|---|---|
| ||||
Posted in reply to French Football | On Mon, 21 Sep 2015 15:38:38 +0000, French Football wrote:
> Going through a book on coding in D, http://ddili.org/ders/d.en/foreach.html , I find the following very useful feature:
>
> When two names are specified in the names section [with a plain array],
> they represent an automatic counter and the value of the element,
> respectively:
> foreach (i, element; array) {
> writeln(i, ": ", element);
> }
>
> I understand that foreach is built on top of a for loop... I'm just wondering why I can't access the automatic counter from a doubly linked list, or an associative array, or some range? It's pretty common for me to have to rewrite foreach loops to be for loops when I get to the bottom and realize I need to know where in the sequence I am...
With an associative array the foreach becomes:
foreach (key, value; aa)
For arbitrary ranges you can use std.range.enumerate like this:
foreach (i, element; someRange.enumerate)
|
September 21, 2015 Re: foreach automoatic counter? | ||||
---|---|---|---|---|
| ||||
Posted in reply to French Football | On Monday, 21 September 2015 at 15:38:40 UTC, French Football wrote:
> Going through a book on coding in D, http://ddili.org/ders/d.en/foreach.html , I find the following very useful feature:
>
> When two names are specified in the names section [with a plain array], they represent an automatic counter and the value of the element, respectively:
> foreach (i, element; array) {
> writeln(i, ": ", element);
> }
>
> I understand that foreach is built on top of a for loop... I'm just wondering why I can't access the automatic counter from a doubly linked list, or an associative array, or some range? It's pretty common for me to have to rewrite foreach loops to be for loops when I get to the bottom and realize I need to know where in the sequence I am...
That's because this isn't really a counter. It makes more sens if you think of it as:
foreach (key, value ; array) {
...
}
In the case of an array, the key to access directly a value is its index, and the array is read in its natural order so the 'key' part acts as a counter. If array is an associative array instead of an array, then you get the key and value as well.
If you want a counter, you want to look at std.range.enumerate() which takes a range and returns a tuple (counter, element). The following example demonstrates the two usages with associative arrays:
void main(string[] args)
{
import std.stdio;
import std.range;
bool[int] aa = [0:true, 1:true, 2:false];
writeln("Get keys and values from an AA");
foreach (key, value ; aa) {
writeln(key, ": ", value);
}
writeln;
writeln("Get a counter and the key of an AA");
foreach (count, key ; aa.byKey.enumerate) {
writeln("count: ", count, " key: ", key, " value: ", aa[key]);
}
}
Note that contrary to languages such as PHP, D's associative arrays are unordered so you can't use this counter as an index.
|
September 21, 2015 Re: foreach automoatic counter? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Justin Whear | On Monday, 21 September 2015 at 15:54:06 UTC, Justin Whear wrote: > On Monday, 21 September 2015 at 15:58:12 UTC, cym13 wrote: > Thankyou! .enumerate lets me iterate over a container with a counter. --Related tangential question... If I have a DList, how do I insert into the middle of it? I'm trying .insertAfter but it wants a range and apparently I can only slice an entire Dlist with []. |
September 21, 2015 Re: foreach automoatic counter? | ||||
---|---|---|---|---|
| ||||
Posted in reply to French Football | On Monday, 21 September 2015 at 16:32:25 UTC, French Football wrote: > On Monday, 21 September 2015 at 15:54:06 UTC, Justin Whear wrote: >> > On Monday, 21 September 2015 at 15:58:12 UTC, cym13 wrote: >> > > Thankyou! .enumerate lets me iterate over a container with a counter. > > --Related tangential question... If I have a DList, how do I insert into the middle of it? I'm trying .insertAfter but it wants a range and apparently I can only slice an entire Dlist with []. I had to look into phobos sources (/usr/include/dlang/dmd/std/containers/dlist.d) to find a unittest, and judging from it it seems inserting in the middle of a DList just wasn't taken seriously. @safe unittest { import std.algorithm : equal; auto dl = DList!string(["a", "b", "d"]); dl.insertAfter(dl[], "e"); // insert at the end assert(equal(dl[], ["a", "b", "d", "e"])); auto dlr = dl[]; dlr.popBack(); dlr.popBack(); dl.insertAfter(dlr, "c"); // insert after "b" assert(equal(dl[], ["a", "b", "c", "d", "e"])); } There is however a nicer method using std.ranges: void main(string[] args) { import std.stdio; import std.range; import std.container: DList; auto list = DList!int([1, 2, 3, 5]); list.insertBefore(list[].drop(3), 4); foreach(n ; list) writeln(n); } I hope this is helpful. |
September 21, 2015 Re: foreach automoatic counter? | ||||
---|---|---|---|---|
| ||||
Posted in reply to cym13 | On Monday, 21 September 2015 at 19:23:38 UTC, cym13 wrote:
> On Monday, 21 September 2015 at 16:32:25 UTC, French Football wrote:
>> [...]
>
> I had to look into phobos sources (/usr/include/dlang/dmd/std/containers/dlist.d) to find a unittest, and judging from it it seems inserting in the middle of a DList just wasn't taken seriously.
>
> [...]
Thankyou!
But wow... talk about pulling teeth...
|
September 21, 2015 Re: foreach automoatic counter? | ||||
---|---|---|---|---|
| ||||
Posted in reply to French Football | On Monday, 21 September 2015 at 22:24:22 UTC, French Football wrote:
> On Monday, 21 September 2015 at 19:23:38 UTC, cym13 wrote:
>> On Monday, 21 September 2015 at 16:32:25 UTC, French Football wrote:
>>> [...]
>>
>> I had to look into phobos sources (/usr/include/dlang/dmd/std/containers/dlist.d) to find a unittest, and judging from it it seems inserting in the middle of a DList just wasn't taken seriously.
>>
>> [...]
>
> Thankyou!
>
> But wow... talk about pulling teeth...
Such a unittest should normally be automatically included in online documentation when generating it, I don't know they were an exception...
|
September 21, 2015 Re: foreach automoatic counter? | ||||
---|---|---|---|---|
| ||||
Posted in reply to French Football | On Monday, September 21, 2015 15:38:38 French Football via Digitalmars-d-learn wrote: > Going through a book on coding in D, http://ddili.org/ders/d.en/foreach.html , I find the following very useful feature: > > When two names are specified in the names section [with a plain > array], they represent an automatic counter and the value of the > element, respectively: > foreach (i, element; array) { > writeln(i, ": ", element); > } > > I understand that foreach is built on top of a for loop... I'm just wondering why I can't access the automatic counter from a doubly linked list, or an associative array, or some range? It's pretty common for me to have to rewrite foreach loops to be for loops when I get to the bottom and realize I need to know where in the sequence I am... It's an index, not a counter. In the case of an array, it's what's used to access each element. In the case of an AA, it has no index. It's a set of unordered key-value pairs. So, if you did foreach(i, element; aa) {} what you're really getting is the key and value, not an index and its corresponding element. foreach(key, value; aa) {} would make more sense in that case, but it's merely a change in name. The types and what they represent are the same regardless. In the case of an input range, it doesn't have any kind of index. It's just a list of elements that keep getting popped off in order to iterate through them. And whether any kind of index would even make sense would depend on what the range represents. In the cases where it would make sense, the range is probably a random-access range, in which case, you can use indices explicitly if you want. In general though, if you want a counter for the range that you're indexing, then you can use lockstep to wrap the range, and then when you use it in foreach, you get the count and the element: http://dlang.org/phobos/std_range.html#.lockstep - Jonathan M Davis |
September 22, 2015 Re: foreach automoatic counter? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On 9/21/15 6:49 PM, Jonathan M Davis via Digitalmars-d-learn wrote:
> In general though, if you want a counter for the
> range that you're indexing, then you can use lockstep to wrap the range, and
> then when you use it in foreach, you get the count and the element:
>
> http://dlang.org/phobos/std_range.html#.lockstep
As Justin Whear pointed out, enumerate is better when you have one range.
-Steve
|
Copyright © 1999-2021 by the D Language Foundation