• bearophile (34/36) Jan 19 2011 Now and then I like to test Phobos with simple tasks, to see how it's go...
• Simen kjaeraas (9/47) Jan 19 2011 Why use map()? The correct solution for this looks like so:
• bearophile (6/15) Jan 19 2011 That result is not the requested one:
• bearophile (3/5) Jan 19 2011 Sorry, the last tuple is (30,"cc").
• Simen kjaeraas (15/29) Jan 19 2011 Soz, I read a bit too fast. It /is/ lazy, though perhaps not the way
• bearophile (6/19) Jan 19 2011 D AAs have byKey and byValue that return a lazy iterator. So if we add a...
• Simen kjaeraas (46/49) Jan 19 2011 byKey is essentially an opApply. You have to wrap it in a fiber to make ...
• bearophile (13/15) Jan 20 2011 Thank you for all your code and work.
• spir (22/24) Jan 20 2011 returns a range of key,value tuples, as in Python3. This allows to solve...
• bearophile (12/28) Jan 20 2011 I have added:
• Simen kjaeraas (5/13) Jan 20 2011 And if not necessarily being built-ins, they are useful enough to warran...
bearophile <bearophileHUGS lycos.com> writes:
```Now and then I like to test Phobos with simple tasks, to see how it's going.

This simple task is to create a dynamic array of pairs (tuples) like:
[(10,"aa"), (30,"bb"), (50,"cc")]

from the associative array:
[1:'a', 2:'b', 3:'c']

If possible read things lazily from the associative array.

---------------------

Idiomatic Python2 solution (iteritems is lazy):

d = {1:'a', 2:'b', 3:'c'}
[(k*10, v*2) for k,v in d.iteritems()]

[(10, 'aa'), (20, 'bb'), (30, 'cc')]

---------------------

D2 lazy solution without map():

import std.stdio, std.typecons;
void main() {
auto aa = [1:'a', 2:'b', 3:'c'];
Tuple!(int, string)[] r;
foreach (k, v; aa)
r ~= tuple(k*10, ""~v~v);
writeln(r);
}

---------------------

Alternative D2 lazy solution without append and map():

import std.stdio, std.typecons;
void main() {
auto aa = [1:"a", 2:"b", 3:"c"];
auto r = new Tuple!(int, string)[aa.length];
int count = 0;
foreach (k, v; aa)
r[count++] = tuple(k*10, v~v);
writeln(r);
}

---------------------

Now to test Phobos a little, is it easy to write a D2 lazy version that uses
map()? Are you able to write it? How many tries needs a D2 programmer with
about a month of D2 programming experience to write a correct version that uses
map()?

Bye,
bearophile
```
Jan 19 2011
"Simen kjaeraas" <simen.kjaras gmail.com> writes:
```bearophile <bearophileHUGS lycos.com> wrote:

Now and then I like to test Phobos with simple tasks, to see how it's
going.

This simple task is to create a dynamic array of pairs (tuples) like:
[(10,"aa"), (30,"bb"), (50,"cc")]

from the associative array:
[1:'a', 2:'b', 3:'c']

If possible read things lazily from the associative array.

---------------------

Idiomatic Python2 solution (iteritems is lazy):

d = {1:'a', 2:'b', 3:'c'}
[(k*10, v*2) for k,v in d.iteritems()]

[(10, 'aa'), (20, 'bb'), (30, 'cc')]

---------------------

D2 lazy solution without map():

import std.stdio, std.typecons;
void main() {
auto aa = [1:'a', 2:'b', 3:'c'];
Tuple!(int, string)[] r;
foreach (k, v; aa)
r ~= tuple(k*10, ""~v~v);
writeln(r);
}

---------------------

Alternative D2 lazy solution without append and map():

import std.stdio, std.typecons;
void main() {
auto aa = [1:"a", 2:"b", 3:"c"];
auto r = new Tuple!(int, string)[aa.length];
int count = 0;
foreach (k, v; aa)
r[count++] = tuple(k*10, v~v);
writeln(r);
}

---------------------

Now to test Phobos a little, is it easy to write a D2 lazy version that
uses map()? Are you able to write it? How many tries needs a D2
programmer with about a month of D2 programming experience to write a
correct version that uses map()?

Why use map()? The correct solution for this looks like so:

import std.range;

void main( ) {
auto aa = [1:"a", 2:"b", 3:"c"];
auto result = zip( aa.keys, aa.values );
}

--
Simen
```
Jan 19 2011
bearophile <bearophileHUGS lycos.com> writes:
```Simen kjaeraas:

Why use map()? The correct solution for this looks like so:

import std.range;

void main( ) {
auto aa = [1:"a", 2:"b", 3:"c"];
auto result = zip( aa.keys, aa.values );
}

That result is not the requested one:
[(10,"aa"), (30,"bb"), (50,"cc")]
And that result is not generated by lazily as the task asks (keys and values
return true arrays).

Bye,
bearophile
```
Jan 19 2011
bearophile <bearophileHUGS lycos.com> writes:
``` That result is not the requested one:
[(10,"aa"), (30,"bb"), (50,"cc")]

Sorry, the last tuple is (30,"cc").

Bye,
bearophile
```
Jan 19 2011
"Simen kjaeraas" <simen.kjaras gmail.com> writes:
```On Thu, 20 Jan 2011 02:44:39 +0100, bearophile <bearophileHUGS lycos.com>
wrote:

That result is not the requested one:
[(10,"aa"), (30,"bb"), (50,"cc")]

Sorry, the last tuple is (30,"cc").

And the second is (20,"bb"), I hope. :p

--
Simen
```
Jan 19 2011
"Simen kjaeraas" <simen.kjaras gmail.com> writes:
```On Thu, 20 Jan 2011 02:40:29 +0100, bearophile <bearophileHUGS lycos.com>
wrote:

Simen kjaeraas:

Why use map()? The correct solution for this looks like so:

import std.range;

void main( ) {
auto aa = [1:"a", 2:"b", 3:"c"];
auto result = zip( aa.keys, aa.values );
}

That result is not the requested one:
[(10,"aa"), (30,"bb"), (50,"cc")]
And that result is not generated by lazily as the task asks (keys and
values return true arrays).

Soz, I read a bit too fast. It /is/ lazy, though perhaps not the way
you meant. This returns the right thing, but does not *read* lazily
from the AA, a task I am unsure how, if at all possible, one should
perform.

import std.algorithm;
import std.range;

void main( ) {
auto aa = [1:"a", 2:"b", 3:"c"];
auto result = map!"tuple(a[0]*10,a[1]~a[1])"( zip( aa.keys, aa.values
) );
}

--
Simen
```
Jan 19 2011
bearophile <bearophileHUGS lycos.com> writes:
```Simen kjaeraas:

Soz, I read a bit too fast. It /is/ lazy, though perhaps not the way
you meant. This returns the right thing, but does not *read* lazily
from the AA, a task I am unsure how, if at all possible, one should
perform.

If possible read things lazily from the associative array.

D AAs have byKey and byValue that return a lazy iterator. So if we add a
"byItem" or "byPair" or "byKeyValue" you are able to read pairs lazily :-)

import std.algorithm;
import std.range;

void main( ) {
auto aa = [1:"a", 2:"b", 3:"c"];
auto result = map!"tuple(a[0]*10,a[1]~a[1])"( zip( aa.keys, aa.values
) );
}

This is a nice solution I didn't think about, thank you :-) It doesn't read
data lazily from the AA as requested, but it's not bad looking.

Bye and thank you,
bearophile
```
Jan 19 2011
"Simen kjaeraas" <simen.kjaras gmail.com> writes:
```bearophile <bearophileHUGS lycos.com> wrote:

D AAs have byKey and byValue that return a lazy iterator. So if we add a
"byItem" or "byPair" or "byKeyValue" you are able to read pairs lazily
:-)

byKey is essentially an opApply. You have to wrap it in a fiber to make it
work with the range interface:

import std.algorithm;
import std.range;
import std.stdio;
import std.typecons;

class opApplyRange( T ) {
alias int delegate( int delegate( ref T ) ) dgType;
Fiber fib;
T value;
dgType dg;

void fibFun( ) {
dg( ( ref T t ){ value = t; Fiber.yield(); return 0; } );
}

this( dgType _dg ) {
dg = _dg;
fib = new Fiber( &fibFun );
popFront( );
}

property T front( ) {
return value;
}

property bool empty() {
return fib.state == Fiber.State.TERM;
}

void popFront( ) {
if ( !empty ) {
fib.call( );
}
}
}

opApplyRange!T toRange( T )( int delegate( int delegate( ref T ) ) dg ) {
return new opApplyRange!T( dg );
}

void main( ) {
auto aa = [1:"a", 2:"b", 3:"c"];

auto o = map!((a){return tuple(a*10,aa[a]~aa[a]);})( toRange(
aa.byKey() ) );
writeln(typeof(o).stringof);
writeln(array(o));
}

Ugly, but it works.

--
Simen
```
Jan 19 2011
bearophile <bearophileHUGS lycos.com> writes:
```Simen kjaeraas:

byKey is essentially an opApply. You have to wrap it in a fiber to make it
work with the range interface:

Thank you for all your code and work.
I have found a bug (it's not a bug of yours): if I compile your code with
-release, DMD prints:
test.d(45): Error: function D main is a nested function and cannot be accessed
from array
test.d(45): Error: function D main is a nested function and cannot be accessed
from array

Where the line 45 is the one that starts with: auto o = map!(...

I use D associative arrays often (it comes from my Python practice), I suggest
to modify AAs to change byKey() and byValue() into ranges usable with
std.algorithm.
AAs may become iterable with zero method calls too (this is equivalent to byKey
or byValue):
map!q{a*10}([1:2, 3:4])

And I suggest to add a third associative array member function that returns a
range of key,value tuples, as in Python3. This allows to solve the task like
this:
auto r = map!q{ tuple(a[0]*10, a[1]~a[1]) }(aa.byPair());

Bye,
bearophile
```
Jan 20 2011
spir <denis.spir gmail.com> writes:
```On 01/20/2011 11:12 AM, bearophile wrote:
And I suggest to add a third associative array member function that

returns a range of key,value tuples, as in Python3. This allows to solve
auto r = map!q{ tuple(a[0]*10, a[1]~a[1]) }(aa.byPair());

Yes, this is the only nice looking, high-level, and D-style solution.
While I by far prefer avoiding stringcode:
auto r = map!((p) (tuple(p[0]*10, p[1]~p[1])) (aa.byPair());
where p means pair; should be correct, should'nt it?

I think for a newcomer the most difficult part is related to tuples:
* find them (in std.typecons!!!)
* catch after much time, pains, research, they should not even try to
construct a tuple using Tuple!, but using the convenience tuple() func

And also that map expects a range, which an AA is not according to my
trials (code rejected at link time until I used byKey). Or am I wrong?

PS: sh*t, I cannot have this work, what's wrong?

auto pairs = map!
((int i) {return tuple(10*i, aa[i]~aa[i]);})
(aa.byKey());

Denis
_________________
vita es estrany
spir.wikidot.com
```
Jan 20 2011
bearophile <bearophileHUGS lycos.com> writes:
```spir:

Yes, this is the only nice looking, high-level, and D-style solution.

http://d.puremagic.com/issues/show_bug.cgi?id=5466

While I by far prefer avoiding stringcode:
auto r = map!((p) (tuple(p[0]*10, p[1]~p[1])) (aa.byPair());
where p means pair; should be correct, should'nt it?

If you use a lambda template you need braces and the return statement:
auto r = map!((p){ return tuple(p[0]*10, p[1]~p[1]); })(aa.byPair());

I think for a newcomer the most difficult part is related to tuples:
* find them (in std.typecons!!!)
* catch after much time, pains, research, they should not even try to
construct a tuple using Tuple!, but using the convenience tuple() func

I agree that like dynamic arrays, tuples are better as built-ins, in D too.
Another very useful thing is tuple unpacking syntax:
http://d.puremagic.com/issues/show_bug.cgi?id=4579

And also that map expects a range, which an AA is not according to my
trials (code rejected at link time until I used byKey). Or am I wrong?

You aren't wrong.

PS: sh*t, I cannot have this work, what's wrong?

auto pairs = map!
((int i) {return tuple(10*i, aa[i]~aa[i]);})
(aa.byKey());

Look at the answers by Simen kjaeraas in this thread, he has explained the
situation.

Bye,
bearophile
```
Jan 20 2011
"Simen kjaeraas" <simen.kjaras gmail.com> writes:
```bearophile <bearophileHUGS lycos.com> wrote:

I think for a newcomer the most difficult part is related to tuples:
* find them (in std.typecons!!!)
* catch after much time, pains, research, they should not even try to
construct a tuple using Tuple!, but using the convenience tuple() func