September 03, 2015
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

September 03, 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
September 04, 2015
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.
September 04, 2015
On Friday, 4 September 2015 at 00:18:15 UTC, Namal wrote:
> On Thursday, 3 September 2015 at 23:54:44 UTC, H. S. Teoh wrote:
>> [...]
>
> 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.


My 2 cents, as someone who is newish to D, I'd also recommend the above approach. I found the whole ranges thing to be hard to get at first, but I do find myself using ranges + std.algorithm more and more (even though it's mostly just basic map and filter).
September 04, 2015
On Fri, Sep 04, 2015 at 12:18:14AM +0000, Namal via Digitalmars-d-learn wrote: [...]
> 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.

Arrays and strings are built into the language; but many common operations on arrays and strings are not built-in, but are provided in the standard library, i.e., std.array and std.string.

So if you use just the plain ~, ~=, operators, then you don't need
std.array or std.string. But if you need functions like split() or
array(), then you need to import std.array.  If you're only dealing with
strings as char arrays, then that's all you need. But if you want some
string-specific functions, e.g., isNumeric(), chomp(), capitalize(),
etc., then you need std.string.

Also, some of the more generic operations that can be applied to more
than just arrays or strings, will be found in std.algorithm, such as
map(), find(), count(), startsWith(), etc..

Basically, if an operation *only* applies to strings, it should generally be found in std.string; if it can also apply to arrays, then it should be found in std.array. If it can be applied to more than just arrays (that is, ranges, e.g., a file stream, a network socket, a sequence of values produced by a generating function, etc., anything with array-like sequential semantics that are not necessarily actual arrays), then it will generally be found in std.algorithm.  One useful rule-of-thumb to decide where to look is to ask yourself if an operation on an array can also be logically applied to a linked-list. If it can, it's probably in std.algorithm. If not (i.e. it depends on semantics specific to arrays), then it's probably in std.array.

Hope this helps.


T

-- 
Latin's a dead language, as dead as can be; it killed off all the Romans, and now it's killing me! -- Schoolboy
September 04, 2015
> Hope this helps.

Yes, it does. I have a question about arrays. I can sort an array A by sort(A);
How can I get just the maximum element? Do I need to give a range for it?


September 04, 2015
On Friday, 4 September 2015 at 01:31:28 UTC, Namal wrote:
> How can I get just the maximum element? Do I need to give a range for it?

Use max? http://dlang.org/phobos/std_algorithm_comparison.html#max
September 04, 2015
On Friday, 4 September 2015 at 01:55:13 UTC, deed wrote:
> On Friday, 4 September 2015 at 01:31:28 UTC, Namal wrote:
>> How can I get just the maximum element? Do I need to give a range for it?
>
> Use max? http://dlang.org/phobos/std_algorithm_comparison.html#max

Sorry, I don't understand the syntax yet. How do I tell max to search all elements? I mean, why does sort(myarray) is legit and max(myarray) isn't.
September 04, 2015
On Friday, 4 September 2015 at 07:27:54 UTC, Namal wrote:
> On Friday, 4 September 2015 at 01:55:13 UTC, deed wrote:
>> On Friday, 4 September 2015 at 01:31:28 UTC, Namal wrote:
>>> How can I get just the maximum element? Do I need to give a range for it?
>>
>> Use max? http://dlang.org/phobos/std_algorithm_comparison.html#max
>
> Sorry, I don't understand the syntax yet. How do I tell max to search all elements?
You can search all elements by using reduce
http://dlang.org/phobos/std_algorithm_iteration.html#reduce

> I mean, why does sort(myarray) is legit and max(myarray) isn't.
I don't know why, other than that is the current design in Phobos.


import std.algorithm, std.range, std.array, std.string, std.stdio,
std.conv;

int[] arr1 = [1, 2, 30];
//arr1.max.writeln;         // Doesn't work, as you say
arr1.reduce!max.writeln;    // This does. Prints 30.

int[] arr2 = [4, 5, 6];
int[][] arr = [arr1, arr2];
arr.reduce!max.writeln;     // Returns either arr1 or arr2. Element by
                            // element comparison until one is greatest.
                            // Prints arr2, since 1 < 4.
arr.joiner.reduce!max.writeln; // Flattens arr1 and arr2 to one arr and
                            // finds max. Prints 30.

//For your example:
auto f = File("filename", "r");
auto numbers = f            // 1 2 3\n4 5 6
    .byLine                 // ["1 2 3", "4 5 6"]
    .map!(a => a.split)     // [["1", "2", "3"], ["4", "5", "6"]]
    .map!(a => a.to!(int[]))// [[1, 2, 3], [4, 5, 6]]
    .array;                 // Allocates and puts the elements into an
                            // int[][] for reuse of state.

numbers                     // [[1, 2, 3], [4, 5, 6]]
    .map!(reduce!max)       // [3, 6]
    .writeln;               // prints [3, 6]

numbers                     // [[1, 2, 3], [4, 5, 6]]
    .joiner                 // [1, 2, 3, 4, 5, 6]
    .reduce!max             // 6
    .writeln;               // prints 6
September 04, 2015
On Friday, 4 September 2015 at 11:50:23 UTC, deed wrote:
>
> import std.algorithm, std.range, std.array, std.string, std.stdio,
> std.conv;
>
> int[] arr1 = [1, 2, 30];
> //arr1.max.writeln;         // Doesn't work, as you say
> arr1.reduce!max.writeln;    // This does. Prints 30.

Again using reduce is the functional way to do it. The above basically boils down to:

int[] arr1 = [1, 2, 30];
int maxElement = arr1[1];
foreach( element; arr1[2..$] ) //2..$ is short hand for second till last ($) element
{
  maxElement = max( maxElement, element );
}
writeln( maxElement );