digitalmars.D - List comprehensions in D?

• David Medlock (37/37) Jun 25 2006 My meager attempts to clone some list functionality in Python:
• David Medlock (13/18) Jun 25 2006 in addition,
• Rémy Mouëza (6/24) Jun 25 2006 Wonderfull !!!
• Oskar Linde (18/34) Jun 29 2006 Yes, the new delegate syntax is very convenient. The above functions are...
• David Medlock (16/63) Jun 29 2006 I'm not sure, but since arrays are by reference I would prefer to make
• Oskar Linde (21/87) Jun 30 2006 I should have mentioned that the doMap is also an in-place modifying
• David Medlock (26/76) Jun 27 2006 Another useful pair of templates for parsing: skip and collect
David Medlock <noone nowhere.com> writes:
```My meager attempts to clone some list functionality in Python:

r = [ y for y in array if y > 10 ];

thanks to shortened delegate declarations its pretty close in D:
(this is a first stab but I'm sure we can get closer with some hackery)

int[] r = array.where( (int y){ return y>10; } );

and for mutating the array:

int[] r = array.map( (int y){return y + 5;} );

and in place modifications:

array.update( (inout int y){ y+=5; } );

// template code begins

template where(T)
{
T[]   where( T[] arr, bool delegate(T) dg )
{
T[] result ;
foreach( T val; arr ) if ( dg(val) ) result ~= val;
return result;
}
}

template  map(T)
{
T[]   map( T[] arr, T delegate(T) dg )
{
T[] result = new T[arr.length];
for( int n =0; n<arr.length; n++ ) result[n] = dg(arr[n]);
return result;
}
}

template update(T)
{
void  update( T[] arr, void delegate(inout T) dg )
{
foreach( int n,T val; arr ) dg( arr[n] );
}
}

Pretty cool, IMO.
-DavidM
```
Jun 25 2006
David Medlock <ashleymedlock no.spam.yahoo.com> writes:
```David Medlock wrote:
My meager attempts to clone some list functionality in Python:

r = [ y for y in array if y > 10 ];

<snip>
Pretty cool, IMO.
-DavidM

If you consider that arrays are just machine-optimized versions of
maps(or graphs) with the allowed index as integers between 0 and N,
then passing a predicate function on those indexes makes some sense.

for containers: (depending on your view of the syntax)

T[]  opIndex( bool delegate(T) dg ) { return items.where( dg ); }
T[]  opIndexAssign( void delegate( inout T) dg ){ items.update( dg ); }

x = vector[ (int t){return t>5;} ]; // subset of vector
vector[] = (inout int x) { x += 100; } ; // update all members of vector

And of course extending to opSlice/opSliceAssign....

-DavidM
```
Jun 25 2006
Rémy Mouëza <ray.jay.ay.moueza at gmail dot com> <Rémy_member pathlink.com> writes:
```In article <e7mg88\$1mh3\$1 digitaldaemon.com>, David Medlock says...
David Medlock wrote:
My meager attempts to clone some list functionality in Python:

r = [ y for y in array if y > 10 ];

<snip>
Pretty cool, IMO.
-DavidM

If you consider that arrays are just machine-optimized versions of
maps(or graphs) with the allowed index as integers between 0 and N,
then passing a predicate function on those indexes makes some sense.

for containers: (depending on your view of the syntax)

T[]  opIndex( bool delegate(T) dg ) { return items.where( dg ); }
T[]  opIndexAssign( void delegate( inout T) dg ){ items.update( dg ); }

x = vector[ (int t){return t>5;} ]; // subset of vector
vector[] = (inout int x) { x += 100; } ; // update all members of vector

And of course extending to opSlice/opSliceAssign....

-DavidM

Wonderfull !!!
And simply powerfull too !!!

D is looking more and more like a strongly typed Python like language with
braces. Compiled languages can also support high level programming ( if well
designed, but D is indeed ).
```
Jun 25 2006
Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
```David Medlock wrote:
David Medlock wrote:
My meager attempts to clone some list functionality in Python:

r = [ y for y in array if y > 10 ];

<snip>
Pretty cool, IMO.

Yes, the new delegate syntax is very convenient. The above functions are
also in my std.array proposal (under different names). Your update
function with an inout argument instead of my suggested doMap with a
pure functional argument is interesting:

arr.update((inout int x){ x++; });
vs
arr.doMap((int x){ return x+1; });

A smart implementation would be able to support both versions in one
function. I wounder if that is appropriate. It would be helpful if there
were any way to tell if the arguments of a delegate type were
in/out/inout. I guess some .mangleof hackery could help there.

If you consider that arrays are just machine-optimized versions of
maps(or graphs) with the allowed index as integers between 0 and N,
then passing a predicate function on those indexes makes some sense.

for containers: (depending on your view of the syntax)

T[]  opIndex( bool delegate(T) dg ) { return items.where( dg ); }
T[]  opIndexAssign( void delegate( inout T) dg ){ items.update( dg ); }

In my view of the syntax, opIndex(bool delegate) should return a view,
rater then a new array with copied elements, similar to how a slice of
an array returns a view rather than copied elements. A combined
select/update would also be cool:

void opIndexAssign(T delegate(T) updater, bool delegate(T) selecter)

/Oskar
```
Jun 29 2006
David Medlock <noone nowhere.com> writes:
```Oskar Linde wrote:
David Medlock wrote:

David Medlock wrote:

My meager attempts to clone some list functionality in Python:

r = [ y for y in array if y > 10 ];

<snip>

Pretty cool, IMO.

Yes, the new delegate syntax is very convenient. The above functions are
also in my std.array proposal (under different names). Your update
function with an inout argument instead of my suggested doMap with a
pure functional argument is interesting:

arr.update((inout int x){ x++; });
vs
arr.doMap((int x){ return x+1; });

A smart implementation would be able to support both versions in one
function. I wounder if that is appropriate. It would be helpful if there
were any way to tell if the arguments of a delegate type were
in/out/inout. I guess some .mangleof hackery could help there.

I'm not sure, but since arrays are by reference I would prefer to make
update functions named differently (sort and reverse still bite me on
occasion).

If you consider that arrays are just machine-optimized versions of
maps(or graphs) with the allowed index as integers between 0 and N,
then passing a predicate function on those indexes makes some sense.

for containers: (depending on your view of the syntax)

T[]  opIndex( bool delegate(T) dg ) { return items.where( dg ); }
T[]  opIndexAssign( void delegate( inout T) dg ){ items.update( dg ); }

In my view of the syntax, opIndex(bool delegate) should return a view,
rater then a new array with copied elements,

Do you mean a container which transforms the elements passed through
opIndex using the delegate?  That could be an issue with the delegate
going out of scope.

Otherwise I don't see how you could do it without making a new array.

similar to how a slice of
an array returns a view rather than copied elements. A combined
select/update would also be cool:

void opIndexAssign(T delegate(T) updater, bool delegate(T) selecter)

/Oskar

Yes combined functionality is nice and getting close to the list
comprehensions i covet from python.

I also toyed with the idea of using the (just added) opIn operator.

int[] result = container in (int a) {return a>5;};

But this seemed too 'out of the ordinary'.

PS. I will be glad to see your array lib in phobos.

-DavidM
```
Jun 29 2006
Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
```David Medlock wrote:
Oskar Linde wrote:
David Medlock wrote:

David Medlock wrote:

My meager attempts to clone some list functionality in Python:

r = [ y for y in array if y > 10 ];

<snip>

Pretty cool, IMO.

Yes, the new delegate syntax is very convenient. The above functions
are also in my std.array proposal (under different names). Your update
function with an inout argument instead of my suggested doMap with a
pure functional argument is interesting:

arr.update((inout int x){ x++; });
vs
arr.doMap((int x){ return x+1; });

A smart implementation would be able to support both versions in one
function. I wounder if that is appropriate. It would be helpful if
there were any way to tell if the arguments of a delegate type were
in/out/inout. I guess some .mangleof hackery could help there.

I'm not sure, but since arrays are by reference I would prefer to make
update functions named differently (sort and reverse still bite me on
occasion).

I should have mentioned that the doMap is also an in-place modifying
function. I agree that such functions should preferably have a different
name, and that is the reason for the "do"-prefix. update is a nice and
clear name though.

I also find the behavior of sort and reverse to be unfortunate. For
example, I've more than once seen code similar to:

foreach(x ; arr.reverse) {...},

where I believe the side effect was unintentional. Since .sort and
.reverse are now fully library-implementable (sans the lacking trailing
parentheses), I think they should be made depreciated at some point.

If you consider that arrays are just machine-optimized versions of
maps(or graphs) with the allowed index as integers between 0 and N,
then passing a predicate function on those indexes makes some sense.

for containers: (depending on your view of the syntax)

T[]  opIndex( bool delegate(T) dg ) { return items.where( dg ); }
T[]  opIndexAssign( void delegate( inout T) dg ){ items.update( dg ); }

In my view of the syntax, opIndex(bool delegate) should return a view,
rater then a new array with copied elements,

Do you mean a container which transforms the elements passed through
opIndex using the delegate?  That could be an issue with the delegate
going out of scope.

Yes. And you are right.

Otherwise I don't see how you could do it without making a new array.

You could use the delegate to evaluate an index array, but that would
also count as making a new array I guess. :)

similar to how a slice of
an array returns a view rather than copied elements. A combined
select/update would also be cool:

void opIndexAssign(T delegate(T) updater, bool delegate(T) selecter)

Yes combined functionality is nice and getting close to the list
comprehensions i covet from python.

I also toyed with the idea of using the (just added) opIn operator.

int[] result = container in (int a) {return a>5;};

But this seemed too 'out of the ordinary'.

PS. I will be glad to see your array lib in phobos.

Thanks. I'm actually not very concerned about getting /my/ library in
phobos, but I would certainly like to see /a/ library there.

Sadly, D's incomplete ifti support is an inhibiting factor that makes
writing template libraries more awkward than needed. The uncertainty
regarding when and how we can expect an improvement doesn't help either.

Regards,

Oskar
```
Jun 30 2006
David Medlock <noone nowhere.com> writes:
```David Medlock wrote:
My meager attempts to clone some list functionality in Python:

r = [ y for y in array if y > 10 ];

thanks to shortened delegate declarations its pretty close in D:
(this is a first stab but I'm sure we can get closer with some hackery)

int[] r = array.where( (int y){ return y>10; } );

and for mutating the array:

int[] r = array.map( (int y){return y + 5;} );

and in place modifications:

array.update( (inout int y){ y+=5; } );

// template code begins

template where(T)
{
T[]   where( T[] arr, bool delegate(T) dg )
{
T[] result ;
foreach( T val; arr ) if ( dg(val) ) result ~= val;
return result;
}
}

template  map(T)
{
T[]   map( T[] arr, T delegate(T) dg )
{
T[] result = new T[arr.length];
for( int n =0; n<arr.length; n++ ) result[n] = dg(arr[n]);
return result;
}
}

template update(T)
{
void  update( T[] arr, void delegate(inout T) dg )
{
foreach( int n,T val; arr ) dg( arr[n] );
}
}

Pretty cool, IMO.
-DavidM

Another useful pair of templates for parsing: skip and collect

// skip whitespace during parsing
char[] r = text.skip( (char c){ return c<=32; } );

// get the next token from the input text
char[] tok = text.collect( (char c){return isalnum(c)!=0; } );

template skip(T)
{
T[]  skip( T[] arr, bool delegate(T) dg )
{
int count = 0;
foreach( T val; arr ) if ( dg( arr[count] )) count++; else break;
return arr[count..arr.length];
}
}

template collect(T)
{
T[]  collect( T[] arr, bool delegate(T) dg )
{
int count = 0;
foreach( T val; arr ) if ( dg( arr[count] )) count++; else break;
return arr[0..count];
}
}

Love the new syntax, so clean.
-DavidM
```
Jun 27 2006