我有以下函数findFirstDuplicateFrequency,它(正确地)实现了编程拼图的算法。
我想推广D的功能特征,并认为我可以将reduce应用于这个问题,而不是强制循环。
我遇到一个问题,需要能够多次(但未知)迭代输入序列,并在满足退出条件时退出处理。
AFAICS的标准减少不能在处理过程中退出,我也在挣扎如何进行额外的累加器信息,用于计算退出条件。
那么什么才是正确的呢?惯用D方法解决问题的(更多)功能?
这是我的第一个D程序,所以所有其他的评论也欢迎!
import std.conv: to;
/**
From: https://adventofcode.com/2018/day/1
You notice that the device repeats the same frequency change list over and
over. To calibrate the device, you need to find the first frequency it reaches
twice.
For example, using the same list of changes above, the device would loop as
follows:
Current frequency 0, change of +1; resulting frequency 1.
Current frequency 1, change of -2; resulting frequency -1.
Current frequency -1, change of +3; resulting frequency 2.
Current frequency 2, change of +1; resulting frequency 3.
(At this point, the device continues from the start of the list.)
Current frequency 3, change of +1; resulting frequency 4.
Current frequency 4, change of -2; resulting frequency 2, which has already been seen.
In this example, the first frequency reached twice is 2. Note that your device
might need to repeat its list of frequency changes many times before a
duplicate frequency is found, and that duplicates might be found while in the
middle of processing the list.
Here are other examples:
+1, -1 first reaches 0 twice.
+3, +3, +4, -2, -4 first reaches 10 twice.
-6, +3, +8, +5, -6 first reaches 5 twice.
+7, +7, -2, -7, -4 first reaches 14 twice.
What is the first frequency your device reaches twice?
*/
int findFirstDuplicateFrequency(int[] frequencyChanges)
pure
{
int[int] alreadySeen = [0:1];
int frequency = 0;
out_: while(true) {
foreach(change; frequencyChanges) {
frequency += change;
if (int* _ = frequency in alreadySeen) {
break out_;
} else {
alreadySeen[frequency] = 1;
}
}
}
return frequency;
} unittest {
int answer = 0;
answer = findFirstDuplicateFrequency([1, -2, 3, 1]);
assert(answer == 2, "Got: " ~ to!string(answer));
answer = findFirstDuplicateFrequency([1, -1]);
assert(answer == 0, "Got: " ~ to!string(answer));
answer = findFirstDuplicateFrequency([3, 3, 4, -2, -4]);
assert(answer == 10, "Got: " ~ to!string(answer));
answer = findFirstDuplicateFrequency([-6, 3, 8, 5, -6]);
assert(answer == 5, "Got: " ~ to!string(answer));
answer = findFirstDuplicateFrequency([7, 7, -2, -7, -4]);
assert(answer == 14, "Got: " ~ to!string(answer));
}
void main() {}发布于 2018-12-15 12:09:30
即使根据@AdamD.Ruppe的说法,让代码更“功能化”也没有太大的希望,我受到@BioTronic的cumulativeFold + until提示的启发,决定再看一遍。
不幸的是,我看不到应用cumulativeFold + until的方法,因为我没有until所需的哨位值,而且仍然存在与reduce相同的停止问题。
在浏览标准运行库引用时,我注意到each确实有一个早期退出(也称为部分迭代)选项。我还遇到了std.range.cycle。
结合这两个闪亮的新事物,我找到了下面的解决方案。findFirstDuplicateFrequencyV2使用cycle和each替换第一个版本的命令式循环。我不确定这个版本是否更简单,但希望它更“时髦”!
int findFirstDuplicateFrequencyV2(int[] frequencyChanges)
pure
{
import std.algorithm.iteration : each;
import std.range : cycle;
import std.typecons : Yes, No;
int[int] alreadySeen = [0:1];
int frequency = 0;
frequencyChanges.cycle.each!((change) {
frequency += change;
if (frequency in alreadySeen) {
return No.each;
}
alreadySeen[frequency] = 1;
return Yes.each;
});
return frequency;
} unittest {
import std.conv : to;
int answer = 0;
answer = findFirstDuplicateFrequencyV2([1, -2, 3, 1]);
assert(answer == 2, "Got: " ~ to!string(answer));
answer = findFirstDuplicateFrequencyV2([1, -1]);
assert(answer == 0, "Got: " ~ to!string(answer));
answer = findFirstDuplicateFrequencyV2([3, 3, 4, -2, -4]);
assert(answer == 10, "Got: " ~ to!string(answer));
answer = findFirstDuplicateFrequencyV2([-6, 3, 8, 5, -6]);
assert(answer == 5, "Got: " ~ to!string(answer));
answer = findFirstDuplicateFrequencyV2([7, 7, -2, -7, -4]);
assert(answer == 14, "Got: " ~ to!string(answer));
}https://stackoverflow.com/questions/53700781
复制相似问题