Jump to page: 1 2
Thread overview
how to skip the next (n) item & continue from (n+1) with a range ? e.g. in File(fn).byLine();
Jun 22, 2020
mw
Jun 22, 2020
mw
Jun 22, 2020
mw
Jun 22, 2020
mw
Jun 22, 2020
H. S. Teoh
Jun 22, 2020
mw
Jun 22, 2020
mw
Jun 22, 2020
Ali Çehreli
Jun 22, 2020
mw
Jun 23, 2020
Ali Çehreli
Jun 22, 2020
kinke
Jun 22, 2020
kinke
June 22, 2020
Hi,

I need this logic:

```
auto range = File(fn).byLine();
foreach (line; range) {
  if (comeCond(line)) {
     // skip the next n line
     // and continue the foreach loop from the (n+1) line
  } else {
     regularProcess(line);
  }
}
```

Is it possible to do this in a foreach loop?

If not, how can I achieve that, esp. when reading a file line-by-line?
do I have to read the whole file into memory, and split by line and using regular `for` loop?

June 22, 2020
On 6/22/20 3:53 PM, mw wrote:
> Hi,
> 
> I need this logic:
> 
> ```
> auto range = File(fn).byLine();
> foreach (line; range) {
>    if (comeCond(line)) {
>       // skip the next n line
>       // and continue the foreach loop from the (n+1) line
>    } else {
>       regularProcess(line);
>    }
> }
> ```
> 
> Is it possible to do this in a foreach loop?

I wouldn't recommend it, instead do a while loop:

auto range = File(fn).byLine;

while(!range.empty)
{
   auto line = range.front;
   if(someCond(line)) {
        range.popFrontN(n);
   } else {
        regularProcess(line);
        range.popFront;
   }
}

-Steve
June 22, 2020
If you are referring to the next line, not the next n lines, that's a simple `continue;` statement.
June 22, 2020
On Monday, 22 June 2020 at 20:02:22 UTC, kinke wrote:
> If you are referring to the next line, not the next n lines, that's a simple `continue;` statement.

[Please discard, that'd obviously be skipping the *current* line.]
June 22, 2020
On Monday, 22 June 2020 at 20:00:50 UTC, Steven Schveighoffer wrote:
> I wouldn't recommend it, instead do a while loop:
>
> auto range = File(fn).byLine;
>
> while(!range.empty)
> {
>    auto line = range.front;
>    if(someCond(line)) {
>         range.popFrontN(n);
>    } else {
>         regularProcess(line);
>         range.popFront;
>    }
> }

Thanks.

so `front` is peek, and `popFront` is the pop action whose return type is `void`, why we need two *separate* calls instead of just let `popFront` return T (or do we have another function for this)? i.e if the user forget `popFront`, it will prone to infinite loop bug?

June 22, 2020
On Monday, 22 June 2020 at 20:46:30 UTC, mw wrote:
> On Monday, 22 June 2020 at 20:00:50 UTC, Steven Schveighoffer wrote:
>> I wouldn't recommend it, instead do a while loop:
>>
>> auto range = File(fn).byLine;
>>
>> while(!range.empty)
>> {
>>    auto line = range.front;
>>    if(someCond(line)) {
>>         range.popFrontN(n);

I'm asking this, because here it need to be range.popFrontN(n+1);

i.e. bug-prone

can be fixed by:
   auto line = range.front;
   range.popFront;  // pop immediately


>>    } else {
>>         regularProcess(line);
>>         range.popFront;
>>    }
>> }
>
> Thanks.
>
> so `front` is peek, and `popFront` is the pop action whose return type is `void`, why we need two *separate* calls instead of just let `popFront` return T (or do we have another function for this)? i.e if the user forget `popFront`, it will prone to infinite loop bug?

so my question.
June 22, 2020
On Monday, 22 June 2020 at 20:49:55 UTC, mw wrote:
> On Monday, 22 June 2020 at 20:46:30 UTC, mw wrote:
>> On Monday, 22 June 2020 at 20:00:50 UTC, Steven Schveighoffer wrote:
>>> I wouldn't recommend it, instead do a while loop:
>>>
>>> auto range = File(fn).byLine;
>>>
>>> while(!range.empty)
>>> {
>>>    auto line = range.front;
>>>    if(someCond(line)) {
>>>         range.popFrontN(n);
>
> I'm asking this, because here it need to be

either

> range.popFrontN(n+1);
>
> i.e. bug-prone

or

> can be fixed by:
>    auto line = range.front;
>    range.popFront;  // pop immediately

of course.
June 22, 2020
On 6/22/20 1:46 PM, mw wrote:

> so `front` is peek, and `popFront` is the pop action whose return type
> is `void`, why we need two *separate* calls instead of just let
> `popFront` return T

Others have other explanations for this but my understanding is about exception safety: If it changed internal state and returned the front object, you would no be able to make a function like popFront() strongly exception safe. (There are ample documentation for this topic in C++ circles.)

Another reason is cohesion: We want functions to have as little responsibility as possible (ideally single).

> (or do we have another function for this)?

There are many useful functions in std.range:

  https://dlang.org/phobos/std_range.html

The "take" and "drop" functions may be useful.

Ali

June 22, 2020
On Mon, Jun 22, 2020 at 08:51:49PM +0000, mw via Digitalmars-d-learn wrote: [...]
> >    auto line = range.front;
> >    range.popFront;  // pop immediately
[...]

This is dangerous, because it assumes .front is not invalidated by .popFront.  It will not work, for example, with byLine because .front returns a buffer which is reused by .popFront (a so-called "transient range").

In the realm of defensive programming, it is better to make less assumptions (don't assume .front remains valid after .popFront) than add implicit assumptions (range is non-transient) that may break in subtle ways that are not immediately obvious.


T

-- 
Why ask rhetorical questions? -- JC
June 22, 2020
On 6/22/20 4:49 PM, mw wrote:
> On Monday, 22 June 2020 at 20:46:30 UTC, mw wrote:
>> On Monday, 22 June 2020 at 20:00:50 UTC, Steven Schveighoffer wrote:
>>> I wouldn't recommend it, instead do a while loop:
>>>
>>> auto range = File(fn).byLine;
>>>
>>> while(!range.empty)
>>> {
>>>    auto line = range.front;
>>>    if(someCond(line)) {
>>>         range.popFrontN(n);
> 
> I'm asking this, because here it need to be range.popFrontN(n+1);

`n` actually isn't defined, you defined it in a comment in your original code ;) I just threw it in there. Of course, make sure it works how you are expecting, I don't know what your code is doing.

> 
> i.e. bug-prone
> 
> can be fixed by:
>     auto line = range.front;
>     range.popFront;  // pop immediately

This is a bad idea, once you popFront, the original front is possibly invalid (and technically is the case for byLine).

> 
> 
>>>    } else {
>>>         regularProcess(line);
>>>         range.popFront;
>>>    }
>>> }
>>
>> Thanks.
>>
>> so `front` is peek, and `popFront` is the pop action whose return type is `void`, why we need two *separate* calls instead of just let `popFront` return T (or do we have another function for this)? i.e if the user forget `popFront`, it will prone to infinite loop bug?
> 
> so my question.

There is no requirement to actually construct members. e.g. popFrontN calls popFront N times, but does not actually invoke front at all.

Separating the concerns is for correctness and performance.

-Steve
« First   ‹ Prev
1 2