www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - For loop with separator

reply Q. Schroll <qs.il.paperinik gmail.com> writes:
Probably you've come over this problem once in a while, too.
You have a repeating solution, so you use a for(each) loop.
Sometimes, there is an action to be performed between the end of 
one iteration and the beginning of the next, if there is one. The 
prime example is printing the comma when printing a list: There 
is one between any two elements, but neither is one at front or 
behind the last one.

Typical solutions I employed were:
1 Handling the first element separately
2 Condition in the loop, that is false exactly for the first 
iteration.

1 can be done with ranges easily:

if (!range.empty)
{
     action(range.front);
     range.popFront;
     foreach (element; range)
     {
         betweenAction();
         action(element);
     }
}

This approach is clearly quite verbose for the problem, but 
there's nothing done unnecessarily.

2 can be done easily, too:

foreach (i, element; range)
{
     if (i > 0) betweenAction();
     action(element);
}

While 2 is less code, it's prone to be checked every iteration.
Note that 2 is rather D specific in its length. It can be done in 
other languages, but is more verbose.

Is there a cleaner solution that I missed?
Jul 04 2019
next sibling parent Alex <sascha.orlov gmail.com> writes:
On Thursday, 4 July 2019 at 17:00:33 UTC, Q. Schroll wrote:
 Probably you've come over this problem once in a while, too.
 You have a repeating solution, so you use a for(each) loop.
 Sometimes, there is an action to be performed between the end 
 of one iteration and the beginning of the next, if there is 
 one. The prime example is printing the comma when printing a 
 list: There is one between any two elements, but neither is one 
 at front or behind the last one.

 Typical solutions I employed were:
 1 Handling the first element separately
 2 Condition in the loop, that is false exactly for the first 
 iteration.

 1 can be done with ranges easily:

 if (!range.empty)
 {
     action(range.front);
     range.popFront;
     foreach (element; range)
     {
         betweenAction();
         action(element);
     }
 }

 This approach is clearly quite verbose for the problem, but 
 there's nothing done unnecessarily.

 2 can be done easily, too:

 foreach (i, element; range)
 {
     if (i > 0) betweenAction();
     action(element);
 }

 While 2 is less code, it's prone to be checked every iteration.
 Note that 2 is rather D specific in its length. It can be done 
 in other languages, but is more verbose.

 Is there a cleaner solution that I missed?
As far as I can interpret it, joiner https://dlang.org/library/std/algorithm/iteration/joiner.html uses roughly the first approach.
Jul 04 2019
prev sibling parent reply berni <someone somewhere.com> writes:
On Thursday, 4 July 2019 at 17:00:33 UTC, Q. Schroll wrote:
 The prime example is printing the comma when printing a list: 
 There is one between any two elements, but neither is one at 
 front or behind the last one.
If it is just for printing commas in between, you can use range.join(", ") https://dlang.org/phobos/std_array.html#.join
Jul 06 2019
parent a11e99z <black80 bk.ru> writes:
On Saturday, 6 July 2019 at 11:48:42 UTC, berni wrote:
 On Thursday, 4 July 2019 at 17:00:33 UTC, Q. Schroll wrote:
 The prime example is printing the comma when printing a list: 
 There is one between any two elements, but neither is one at 
 front or behind the last one.
If it is just for printing commas in between, you can use range.join(", ") https://dlang.org/phobos/std_array.html#.join
.map!(e=>e.text).join( ", "); // map for non strings or .format!"%(%s, %)"; // for anything
Jul 06 2019