我碰巧需要同时找到数组的最大值和最小值,所以我决定在D中实现一个minMax函数。
问题:
谢谢!
import std.range;
import std.traits;
import std.typecons;
import std.functional;
class EmptyContainerException : Exception {
this(string msg, string file = __FILE__, size_t line = __LINE__) {
super(msg, file, line);
}
}
// returns a tuple containing the minimum and maximum elements of a finite InputRange
template minMax(alias pred = "a") {
alias map = unaryFun!pred;
auto minMax(Range)(Range r)
if(isInputRange!Range && !isInfinite!Range && is(typeof(map(r.front)))) {
if(r.empty) {
throw new EmptyContainerException(
"minMax expected a container with at least 1 element, got an empty container."
);
}
auto front = r.front;
auto frontMap = map(front);
auto min = front;
auto max = front;
auto minMap = frontMap;
auto maxMap = frontMap;
r.popFront;
while(!r.empty) {
front = r.front;
frontMap = map(front);
if(frontMap > maxMap) {
max = front;
maxMap = frontMap;
}
if(frontMap < minMap) {
min = front;
minMap = frontMap;
}
r.popFront;
}
return tuple!("min", "max")(min, max);
}
}
unittest {
import std.exception : assertThrown;
int[] test1 = [1, 2, 3, 4, 5];
auto test1result = test1.minMax;
assert(test1result.min == 1 && test1result.max == 5);
string test2 = "Hello, World!";
auto test2result = test2.minMax;
assert(test2result.min == ' ' && test2result.max == 'r');
int[] test3 = [];
assertThrown!EmptyContainerException(test3.minMax);
string[] test4 = ["who", "is", "the", "longest", "word"];
auto test4result = test4.minMax!"a.length";
assert(test4result.min == "is" && test4result.max == "longest");
}发布于 2018-06-19 07:05:31
这是一个有效的实现吗?
是啊。它精确地每项调用一次map,否则只执行常规的范围调用。在某些情况下,专门的实现可能更高效(但可能只在使用向量指令的情况下),并行实现也是如此,但这两种实现都不像代码那样具有通用性。
有可读性吗?
当然,这是我见过的最易读的代码之一。循环的内容有些密集。你也许可以让它不像这样密集:
auto front = tuple!("elem", "map")(r.front, map(r.front));
auto min = front;
auto max = front;
r.popFront;
foreach (e; r) {
front = tuple(e, map(e));
if(front.map > max.map) max = front;
if(front.map < min.map) min = front;
}
return tuple!("min", "max")(min.elem, max.elem);除此之外,我什么都没有。
如有任何一般性反馈,将不胜感激。
正如上面一节所暗示的那样,您可能希望使用while (!empty)而不是foreach。这将您的代码减少一行(r.popFront()),并使您更清楚地知道,您将遍历范围中的每个元素。它不应该以任何方式改变代码的性能。
您应该在模板上添加一个if (is(typeof(unaryFun!pred)))约束,这样函数的用户就会在他或她试图用arr.minMax!"invalid string"实例化它的行上得到一条错误消息。
另外,pred的名称是错误的-- 谓词是布尔值函数,如equal、same color或contains bees.我叫它Fn或Fun。
作为次要的nit,我还会将map的名称更改为fn或fun (注意大写的不同)。这是因为我一直把你的map和std.algorithm.map混为一谈。这个概念是正确的,但本质上这个名字已经被取走了。
总之,非常好-我唯一的评论基本上是吹毛求疵。
https://codereview.stackexchange.com/questions/196771
复制相似问题