使用高阶函数在数组中创建重复元素

时间:2018-10-25 18:38:42

标签: d

此处是D语言的新功能。我正在尝试使用高阶函数(即fold!,reduce!,filter!,map!)来创建数组元素的重复项。我宣布我的通用函数为纯函数,并尝试以单行函数的形式完成此任务。我到目前为止最接近的是

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

但这给了我以下输出

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

而不是我真正想要的

[1, 1, 2, 2]

我这样调用函数

writeln(dupList(nums));

我一直在尝试使用reduce代替它,但是当我将map切换为reduce时,出现以下错误:

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)

对于至少了解前三个错误以及我的功能出现问题的任何帮助/建议,将不胜感激。

2 个答案:

答案 0 :(得分:1)

我假设您打算调用map!(a => a.repeat(2))(list)list.map!(a=>a.repeat(2))(两者相同),因为如果您不将实际列表传递给函数,则实际上不会调用它!

无论如何,map和reduce都不会自己完成您想要的事情。 Map会转换单个元素,但不能添加或删除元素。 Reduce(和btw fold,它们基本上是相同的)遍历数组,并且...好吧,将其缩减为仅一个元素,就像求和函数将数组1,2,3变成单个元素6。您想要添加元素,那么您将需要其他东西。

但是首先,有一个回避措施:您的reduce调用由于传递了错误的参数而无法编译(或者,错误消息确实很糟糕并且很难阅读,而没有直接引用的代码也无法打开,但它绝对是指lambda)。将其传递给您的dupList不起作用,因为dupList接受一个数组,但是reduce一次只能使用两个元素,例如sum(a, b)

无论如何,回到要点,您可能获得的最接近的结果可能是在map外部运行另一个函数来展平结果数组,或者换句话说,将它们连接在一起。有一个功能:http://dpldocs.info/experimental-docs/std.algorithm.iteration.joiner.2.html

建议一个可能的答案:

    return list .map!(a => a.repeat(2)) .joiner;

顺便说一句:一线功能被严重高估了。通常最好将其写在多行上,即使仅作为一条语句,也可以这样做,但是您可以在错误消息中获得唯一的行号。我希望将其写成这样:

    return
            list
                    .map!(a => a.repeat(2))
                    .joiner
            ;

因此,每一行代表该过程的单个步骤。当然,确切的格式取决于您,但是我喜欢这种稍微扩展的方法,用于(稍微)更好的错误消息,以及在编辑之前,之后,中间等添加注释或更多内容的视图时,视图更轻松。< / p>

答案 1 :(得分:1)

map本质上将每个元素替换为对该元素调用传递的函数的结果。由于您的函数返回的是两个int的数组,因此结果将是一个数组数组,每个元素都包含两个int

有了这些知识,我们可以使用std.algorith.iteration.joiner

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

您注意到,也可以使用reduce,但这有点复杂:

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

更复杂的原因是:

1)reduce的函数接受两个参数-到目前为止的归约结果和下一个元素。

2)reduce假定传递的数组的第一个元素是精简的起点,除非传递了种子值。由于第一个元素是int,而不是int[],因此我们需要传递种子值。 []不会执行,因为它的类型为void[],所以我们需要创建一个空的int[]。可以使用new int[0]或如上所述的(int[]).init来完成。

希望这会有所帮助-如果还有其他问题,请询问! :)