Thread overview
Re: Make a hash out of two ranges
Feb 28, 2013
Andrej Mitrovic
Feb 28, 2013
bearophile
Feb 28, 2013
Chris Cain
Feb 28, 2013
Andrej Mitrovic
Feb 28, 2013
Chris Cain
Feb 28, 2013
Andrej Mitrovic
Feb 28, 2013
Philippe Sigaud
Feb 28, 2013
Jonathan M Davis
Feb 28, 2013
Andrej Mitrovic
Feb 28, 2013
Andrej Mitrovic
February 28, 2013
On 2/28/13, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:
> import std.algorithm;
> import std.range;
>
> void main()
> {
>     auto r = map!((a, b) => [a : b])(["foo"], ["bar"]);  // error
>     assert(r.front == ["foo" : "bar"]);
> }
>
> This doesn't compile, what am I missing?
>

A more clearer example:

void main()
{
    auto r = map!((a, b) => [a : b])([1, 3], [2, 4]);
    assert(r[0] == [1 : 2]);
    assert(r[1] == [3 : 4]);
}
February 28, 2013
On Thursday, February 28, 2013 04:56:48 Andrej Mitrovic wrote:
> import std.algorithm;
> import std.range;
> 
> void main()
> {
>     auto r = map!((a, b) => [a : b])(["foo"], ["bar"]);  // error
>     assert(r.front == ["foo" : "bar"]);
> }
> 
> This doesn't compile, what am I missing?

Map only works on one range. You can't pass it two of them at the same time. You'd need to wrap them in a single range of pairs with something like zip.

- Jonathan M Davis
February 28, 2013
Andrej Mitrovic:

>> This doesn't compile, what am I missing?

See:
http://dlang.org/phobos/std_array.html#.assocArray
February 28, 2013
On Thursday, 28 February 2013 at 03:59:16 UTC, Andrej Mitrovic wrote:
> void main()
> {
>     auto r = map!((a, b) => [a : b])([1, 3], [2, 4]);
>     assert(r[0] == [1 : 2]);
>     assert(r[1] == [3 : 4]);
> }

Map in std.algorithm doesn't really work like that. Many languages use "map" to mean hashing items, but "map" in functional programming (and D) really means something more like "apply this function to each item."

So, if you did something like this:

    auto arr = [1,3];
    auto r = map!(a => a + 1)(arr);
    assert(r[0] == 2); // because arr[0] + 1 == 2 ... f(arr[0]) = f(1) = 1 + 1 = 2
    assert(r[1] == 4); // because arr[1] + 1 == 4 ... f(arr[1]) = f(3) = 3 + 1 = 4

Then you'd have the correct idea.

If you're trying to create an associative array from two arrays, zip and associative arrays could be handy:
http://dlang.org/phobos/std_range.html#.zip
http://dlang.org/hash-map.html

So, you could use it like so...

    int[int] aa;
    foreach(a, b; zip([1,3], [2,4]))
        aa[a] = b;

    writeln(aa); // prints [1:2, 3:4]
February 28, 2013
On 2/28/13, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
> You'd need to wrap them in a single range of pairs with something like zip.

I'm not exactly sure how to do that though. Just using zip in the argument place won't work.

I've tried to create my own range, but I'm having issues:

import std.string;
import std.stdio;
import std.range;

auto mymap(alias func, Ranges...)(Ranges ranges)
{
    static struct MyMap
    {
        Ranges ranges;

        @property bool empty()
        {
            foreach (ref range; ranges)
                if (range.empty)
                    return true;

            return false;
        }

        @property auto front()
        {
            static string getMixin()
            {
                string[] args;
                foreach (idx; 0 .. Ranges.length)
                    args ~= format("ranges[%s].front", idx);
                return args.join(", ");
            }

            mixin(format(q{
                return func(%s);
            }, getMixin()));
        }

        void popFront()
        {
            foreach (ref range; ranges)
                range.popFront();
        }
    }

    return MyMap(ranges);
}

void main()
{
    auto r = mymap!((a, b) => [a : b])([1, 3], [2, 4]);

    writeln(r.front);  // [1:2]
    r.popFront();
    writeln(r.front);  // [3:4]
    r.popFront();
    // writeln(r.front);  // this would throw as expected

    auto r2 = mymap!((a, b) => [a : b])([1, 3], [2, 4]);
    foreach (x; r2)
        writeln(r2);  // prints "[[1:2], [3:4]]" twice, why?
}
February 28, 2013
On 2/28/13, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:
>     foreach (x; r2)
>         writeln(r2);  // prints "[[1:2], [3:4]]" twice, why?

Oh dumb me I'm priting r2 instead of x, my bad.
February 28, 2013
On 2/28/13, Chris Cain <clcain@uncg.edu> wrote:
> Map in std.algorithm doesn't really work like that. Many languages use "map" to mean hashing items, but "map" in functional programming (and D) really means something more like "apply this function to each item."

I know that, I was expecting it to work with multiple ranges if the functor takes multiple arguments.

> If you're trying to create an associative array from two arrays

A *lazy* range of associative arrays.

On 2/28/13, bearophile <bearophileHUGS@lycos.com> wrote:
> See:
> http://dlang.org/phobos/std_array.html#.assocArray

Same answer as above.

My custom range implementation shows exactly what I was trying to use map for. It only seems natural to me to have this ability, but maybe map!() can't be customized for this use. Anyway I'm satisfied with my approach unless you can make map!() do the same thing with some zip tricks or something.
February 28, 2013
On Thursday, 28 February 2013 at 04:50:34 UTC, Andrej Mitrovic wrote:
> On 2/28/13, Chris Cain <clcain@uncg.edu> wrote:
>> Map in std.algorithm doesn't really work like that. Many
>> languages use "map" to mean hashing items, but "map" in
>> functional programming (and D) really means something more like
>> "apply this function to each item."
>
> I know that, I was expecting it to work with multiple ranges if the
> functor takes multiple arguments.
>
>> If you're trying to create an associative array from two arrays
>
> A *lazy* range of associative arrays.
>

Aha, I see now. Here you go:

    zip([1,3], [2,4])
        .map!(e => [e[0] : e[1]])()
        .writeln();

zip gives out a tuple, so I wish it were possible to do
    .map!((a,b) => [a : b])()
instead and have it appropriately use the elements of the tuple. Maybe that'd be a potential enhancement possibility for map?
February 28, 2013
On 2/28/13, Chris Cain <clcain@uncg.edu> wrote:
> Aha, I see now. Here you go:
>
>      zip([1,3], [2,4])
>          .map!(e => [e[0] : e[1]])()
>          .writeln();

Thanks, I figured this out too by now. :)

But it's definitely nicer having the a/b syntax. I guess I could just overload my map against the phobos map.
February 28, 2013
On Thu, Feb 28, 2013 at 4:14 PM, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:
> On 2/28/13, Chris Cain <clcain@uncg.edu> wrote:
>> Aha, I see now. Here you go:
>>
>>      zip([1,3], [2,4])
>>          .map!(e => [e[0] : e[1]])()
>>          .writeln();
>
> Thanks, I figured this out too by now. :)
>
> But it's definitely nicer having the a/b syntax. I guess I could just overload my map against the phobos map.

Oh, that must be one of the first thing I coded in D, like, 4 years
ago :) Multi-range map + filter + reduce.
Here it is:

https://github.com/PhilippeSigaud/dranges/blob/master/algorithm.d#L176

Ah, good times :) That must be much easier now, since Phobos and DMD are quite better.