Input Range addition to associative arrays

Ali Çehreli acehreli at yahoo.com
Thu Dec 6 19:38:44 PST 2012


On 12/06/2012 11:03 AM, Phil Lavoie wrote:
> Hi,
>
> I am aware that you can iterate over associative arrays in multiple ways
> using the structure's opApply and different delegates returned by
> properties. I think adding a "range" property returning an input range
> to the associative array would benefit the users of the D language.
>
> I'd like to justify this addition by pointing out that some standard
> library functional features, like filter, do not work on associative
> arrays as of right now. The reason for this is that filter returns a
> range that moves to the next appropriate value ON DEMAND rather than
> constructing the result. I think it is a great design choice. However,
> since no incremental (read on demand) iteration can be done on
> associative arrays, one cannot use features such as filter, nor make his
> own.
>
> I think that the existing code can easily support such an addition,
> which makes it all the more attractive.
>
> Imagine that "front()" would return an entry such that entry.key returns
> the key and entry.value returns the value. Here is an example of how one
> could use it:
>
> float[ item ] itemsCost;
> //Items whose price are lower than 5 dollars.
> auto myFavoriteItems = filter!"a.value < 5.0"( itemsCost );
> foreach( cheapItem; myFavoriteItems ) {
> theMoreComplicatedAlgorithmOnEarth( cheapItem); }
>
> Now don't get me wrong, I am aware that you can do this multiple ways.
> It's just that ranges are so attractive in the way they "lazily" fetch
> values that it would make it easier to wrap associative arrays in struct
> that return relevant ranges based on the aa's content of constructing
> the result, than returning the range/or result. I also think it would
> merge well with D's way of doing things.
>
> What are your thoughts?

Makes sense.

Here is a quick and dirty implementation that is based on the assumption 
that byKey and byValue visit the elements in the same order:

import std.stdio;
import std.traits;
import std.algorithm;
import std.array;

struct Element(K, V)
{
     K key;
     V value;
}

struct ByElement(AA)
{
     alias typeof(AA.byKey()) KeyRange;
     alias typeof(AA.byValue()) ValueRange;
     alias Element!(KeyType!AA, ValueType!AA) ElementType;

     KeyRange keys;
     ValueRange values;

     this(AA aa)
     {
         this.keys = aa.byKey();
         this.values = aa.byValue();
     }

     bool empty() const @property
     {
         return keys.empty;
     }

     ElementType front() /* const */ @property
     {
         return ElementType(keys.front, values.front);
     }

     void popFront()
     {
         keys.popFront;
         values.popFront;
     }

     ByElement save()
     {
         return this;
     }
}

ByElement!AA byElement(AA)(AA aa)
{
     return ByElement!AA(aa);
}

void main()
{
     auto aa = [ "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 
5 ];

     writeln(aa
             .byElement
             .filter!(a => a.value % 2)
             .filter!(a => a.key.front == 'o'));
}

Ali


More information about the Digitalmars-d mailing list