Thread overview | ||||||
---|---|---|---|---|---|---|
|
March 11, 2019 Array of byLineCopy ranges behaves as they are byLine | ||||
---|---|---|---|---|
| ||||
Let assume I have multiple files (like "file1", "file2" and so on). I need to iterate them simultaneously with some logic. I have tried to create random access range of ranges, however, it behaves not as expected. Let "file1" is ``` 1 2 3 4 ``` Then this code ```d File[] files; foreach(filename; args[1 .. $]) { files ~= File(filename, "r"); } auto ranges = files.map!(a => a.byLineCopy); writeln(ranges[0].front); writeln(ranges[0].front); writeln(ranges[0].front); ``` produces ``` 1 2 3 ``` Even despite I'm using `byLineCopy`. However, this code ```d File[] files; foreach(filename; args[1 .. $]) { files ~= File(filename, "r"); } auto range = files[0].byLineCopy; writeln(range.front); writeln(range.front); writeln(range.front); ``` produses ``` 1 1 1 ``` as expected. What I'm doing wrong with `map`? Or is this a bug? dmd v2.085.0 P.S. I know that I can call `dup` on `front` and I'm going to do so as workaround. However, I'm curious why current situation is taking place. |
March 11, 2019 Re: Array of byLineCopy ranges behaves as they are byLine | ||||
---|---|---|---|---|
| ||||
Posted in reply to HaraldZealot | On Monday, 11 March 2019 at 15:23:53 UTC, HaraldZealot wrote: > ```d > File[] files; > foreach(filename; args[1 .. $]) > { > files ~= File(filename, "r"); > } > > auto ranges = files.map!(a => a.byLineCopy); > > writeln(ranges[0].front); > writeln(ranges[0].front); > writeln(ranges[0].front); > ``` > produces > ``` > 1 > 2 > 3 > ``` [...] > What I'm doing wrong with `map`? Or is this a bug? `map` is lazy in the sense that it (re-)evaluates the given function whenever you access an element. That means you're calling `byLineCopy` three times on the same file. Your code effectively does this: writeln(files[0].byLineCopy.front); writeln(files[0].byLineCopy.front); writeln(files[0].byLineCopy.front); The range created by `byLineCopy` immediately reads a line from the file to populate its `front`. So you're reading three lines from the file. Strictly speaking, I don't think any of this qualifies as a bug. `map`'s behavior might be surprising, but it's deliberate, as far as I know. To avoid the re-evaluation, assign `ranges[0]` to a variable before using it: auto lines = ranges[0]; writeln(lines.front); writeln(lines.front); writeln(lines.front); That should print the same line three times. |
March 11, 2019 Re: Array of byLineCopy ranges behaves as they are byLine | ||||
---|---|---|---|---|
| ||||
Posted in reply to ag0aep6g | On Monday, 11 March 2019 at 17:04:56 UTC, ag0aep6g wrote: > > To avoid the re-evaluation, assign `ranges[0]` to a variable before using it: > > auto lines = ranges[0]; > writeln(lines.front); > writeln(lines.front); > writeln(lines.front); > > That should print the same line three times. Ah yes, I forget about laziness of `map`. BTW, I have found other solution, which is more fit to my initial intention. ```d ReturnType!(std.stdio.File.byLineCopy!(char, immutable(char)))[] ranges; foreach(filename; args[1 .. $]) { ranges ~= File(filename, "r").byLineCopy; } ``` |
March 11, 2019 Re: Array of byLineCopy ranges behaves as they are byLine | ||||
---|---|---|---|---|
| ||||
Posted in reply to HaraldZealot | On Monday, 11 March 2019 at 17:33:31 UTC, HaraldZealot wrote:
> Ah yes, I forget about laziness of `map`. BTW, I have found other solution, which is more fit to my initial intention.
>
> ```d
> ReturnType!(std.stdio.File.byLineCopy!(char, immutable(char)))[] ranges;
> foreach(filename; args[1 .. $])
> {
> ranges ~= File(filename, "r").byLineCopy;
> }
> ```
An easier way to do this is to use the library function `std.array.array`:
auto ranges = args[1..$].map!(a => File(a, "r").byLineCopy).array;
|
Copyright © 1999-2021 by the D Language Foundation