On Thursday, 3 September 2015 at 23:54:44 UTC, H. S. Teoh wrote:
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

Thx Theo, this and the lack of foolproof tutorials were the reason why I gave up on D 2 years ago and went instead to C++. But I am not giving up this time. That being said, when do I have to import std.array and std.string? Every time I use std.array? I can obviously use arrays and strings without those libs.

Reply via email to