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
mw
Jun 22
mw
Jun 22
mw
Jun 22
mw
Jun 22
mw
Jun 22
mw
Jun 22
mw
Jun 22
kinke
Jun 22
kinke
June 22
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
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
If you are referring to the next line, not the next n lines, that's a simple `continue;` statement.
June 22
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
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
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
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
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
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
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