我想找到循环序列中两个数字之间的最短距离,例如0到6:
library(data.table); library(stringr)
lapply(tstrsplit(my_list, "\\|"), function(s) t(str_split_fixed(s, "--", 2)))
#[[1]]
# [,1] [,2] [,3]
#[1,] "Jan-01" "Jan-01" "Jul-06"
#[2,] "Dec-31" "Jun-30" "Dec-31"
#[[2]]
# [,1] [,2] [,3]
#[1,] "00:00" "12:00" "09:00"
#[2,] "24:00" "18:00" "19:00"
还需要知道哪种“方式”更短(向左或向右)。
所以,如果我的两个数字是0和6,那么通过向后计数(向左),最短距离是1。
以下功能有效,但仅当... 0 1 2 3 4 5 6 0 1 2 3 4 5 6 0 1 2 3 4 5 6 ...
大于next
时才有效。
crt
我无法弄清楚如何让它在两个方面都有效。例如,如果我使用var MAX_NUMBER = 6; // 0 1 2 3 4 5 6 0 1 2 3 4 5 6 0 1 2 3 4 5 6
function shorterDirection(crt, next) {
var toRight = next - crt;
var toLeft = MAX_NUMBER - (next - crt - 1);
return toLeft < toRight ? 'left' : 'right';
}
console.log(shorterDirection(0, 6));
,我希望函数返回shorterDirection(4, 3)
。
答案 0 :(得分:1)
你可以用这个:
function shorterDirection(crt, next) {
var toRight = (next + MAX_NUMBER+1 - crt) % (MAX_NUMBER+1);
return toRight > (MAX_NUMBER+1) / 2 ? 'left' : 'right';
}
请注意,可以有联系。在这种情况下,上述内容将返回left
,即使right
同样出色。
正如你所看到的,那里有很多MAX_NUMBER+1
。如果你有一个常数NUMBER_COUNT
会比你现在拥有的MAX_NUMBER
更大,那就更合适了。
首先写下这个:
var toRight = next - crt;
但当 next 小于 crt 时,这会出现“错误” - 您会得到一个负数。要解决此问题,您需要添加MAX_NUMBER+1
:
var toRight = next + NUMBER+1 - crt;
...但是现在当 next 大于 crt 时,你会得到一个太大的数字。您可以通过减少所需的NUMBER+1
来解决,以便在 0 ... MAX_NUMBER 范围内。这就是modulo(%
)运算符的作用。所以你得到:
var toRight = (next + MAX_NUMBER+1 - crt) % (MAX_NUMBER+1);
一旦你得到了这个结果,你可以推断如果需要超过一半的数字向右移动,你最好向左移动(这将少于数字的一半)。这编码为:
return toRight > (MAX_NUMBER+1) / 2 ? 'left' : 'right';
答案 1 :(得分:1)
你的记法错了。您在Z/7Z
中使用modular arithmetic。
参数应为7
,而不是6
。
我会在一个方向和另一个方向上得到距离并进行比较:
var modulus = 7; /* Z/7Z */
function shorterDirection(crt, next) {
var toRight = (next - crt + modulus) % modulus;
var toLeft = (crt - next + modulus) % modulus;
return toLeft < toRight ? 'left' : 'right';
}
上面的代码假设两个参数都属于{0, ..., modulus-1}
。如果您想允许更宽的范围,例如{modulus+1, ..., modulus-1}
,计算距离的正确方法是
((next - crt) % modulus + modulus) % modulus;
((crt - next) % modulus + modulus) % modulus;