reading file byLine

H. S. Teoh via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Sep 3 16:50:55 PDT 2015


On Thu, Sep 03, 2015 at 11:38:54PM +0000, Namal via Digitalmars-d-learn wrote:
> On Thursday, 3 September 2015 at 23:31:27 UTC, Jordan Wilson wrote:
> >On Thursday, 3 September 2015 at 23:28:37 UTC, Namal wrote:
> >>On Thursday, 3 September 2015 at 23:25:52 UTC, Jordan Wilson wrote:
> >>>And also:
> >>>import std.algorithm
> >>>
> >>>Sorry, I should have taken the time to answer properly and fully.
> >>
> >>import std.file, std.stdio, std.string, std.conv, std.algorithm;
> >>
> >>void main(){
> >>
> >>	auto file = File("text.txt");
> >>	auto numbers = file.byLine()
> >>                 .map!(a => a.split)
> >>                 .map!(a => map!(a => to!int(a))(a))
> >>                 .array();
> >>	
> >>	writeln(numbers);
> >>}
> >>
> >>Error: no property 'array' for type 'MapResult!(__lambda2,
> >>MapResult!(__lambda1, ByLine!(char, char)))'
> >>
> >>Still an error.
> >
> >import std.array
> 
> Thx, finaly, this is so much harder to understand than c++ iostream

I would have written it slightly differently, to emphasize what exactly
is going on:

	auto numbers = File("text.txt")	// read file
		.byLine()		// line by line
		.map!(a => a.split	// split each line into words
			    .map!(a => to!int(a)) // convert each word into int
			    .array)	// collect the ints into an array (per line)
		.array;			// collect all line arrays into one big array

This is the functional way of doing it, of course. If you're more
comfortable with the C++-style imperative approach, you could do this
instead:

	auto file = File("text.txt");
	int[][] numbers;
	foreach (line; file.byLine) {
		auto words = line.split;

		int[] lineNums;
		foreach (word; words) {
			lineNums ~= word.to!int;
		}
		numbers ~= lineNums;
	}

The functional approach is admittedly a bit harder to understand at
first, but it's extremely powerful because it processes everything in a
pipeline, and you can compose operators on the pipeline easily,
rearrange the sequence of operations, etc..

In the imperative nested-loop approach, things quickly get out of hand
once the loop is nested about 2-3 levels deep. A nested loop of 6-7
levels deep would be basically impossible to understand, maintain, or
debug without major refactoring into smaller functions. (In fact,
split() is a library-provided function that basically encapsulates one
of those nested loops.) But if you take the refactoring to its logical
conclusion, you'll eventually end up with a whole bunch of tiny
functions with only a single loop each, each calling the next function
in a chain -- in other words, you arrive at the functional pipeline
approach.  :-)

D allows you to do it either way, but the superior approach IMO is to
learn the functional pipeline approach.


T

-- 
Life is too short to run proprietary software. -- Bdale Garbee


More information about the Digitalmars-d-learn mailing list