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

Reply via email to