Search code examples
d

Creating Duplicate Elements in an Array using Higher-Order Functions


New to D Language here. I'm trying to use higher-order functions (i.e. fold!, reduce!, filter!, map!) to create duplicates of array elements. I'm declaring my generic function as pure and trying to accomplish this task as a one line function. The closest I've come so far is

auto dupList(T)(T[] list) pure { (return map!(a => a.repeat(2)); }

but this gives me the following output

[[1,1],[2,2]]

instead of what I'm actually wanting

[1, 1, 2, 2]

I'm calling the function like so

writeln(dupList(nums));

Instead of using map, I've been trying to use reduce in its place but when I switch out map for reduce I get the following errors:

Error instantiated from here: `staticMap!(ReduceSeedType, __lambda2)` C:\D\dmd2\src\phobos\std\algorithm\iteration.d 3287
Error: template `D_Programs.duplist!int.duplist.__lambda2` cannot deduce function from argument types `!()(int, int)`, candidates are:  C:\D\dmd2\src\phobos\std\algorithm\iteration.d 3696
Error: template instance `D_Programs.duplist!int.duplist.F!(__lambda2)` error instantiating     C:\D\dmd2\src\phobos\std\meta.d 803
Error instantiated from here: `reduce!(int[])` D_Programs.d (refers to dupList)
Error `D_Programs.duplist!int.duplist.__lambda2` D_Programs.d (refers to dupList)
Error instantiated from here: `duplist!int` D_Programs.d (refers to where I'm calling from)

Any help/advice on understanding at least the top three errors and where I'm going wrong with my function would be appreciated.


Solution

  • map essentially replaces each element with the result of calling the passed function on that element. Since your function returns an array of two ints, the result will be an array of arrays, each element holding two ints.

    Armed with this knowledge, we can use std.algorith.iteration.joiner:

    auto dupList(T)(T[] list) pure { return list.map!(a => a.repeat(2)).joiner; }
    

    As you note, it should also be possible to use reduce, but it's a bit more complicated:

    auto dupList(T)(T[] list) pure { return reduce!((a,b) => a~b~b)((T[]).init, list); }
    

    The reasons it's more complicated are:

    1) reduce's function takes two arguments - the result of reducing thus far, and the next element.

    2) reduce assumes the first element of the passed array is the starting point for reduction, unless a seed value is passed. Since the first element is a T, not a T[], we will need to pass a seed value. [] won't do, since it's typed as void[], so we will need to create an empty T[]. This can be done either with new T[0], or as above, (T[]).init.

    Hope this helps - if there are any more questions, please ask! :)