如何让数字在 JavaScript 中的特定范围内循环?
How to get numbers to cycle around specific range in JavaScript?
我有这个不工作,像 1 2 3 4 5 6 7 8 9 1 2 3 4 ...
这样的循环,在 1 和 9 之间循环。
const cycle = integers => {
let i = 0
let x = integers[i++]
while (i < integers.length) {
let y = integers[i++]
const s = x + y
const remainder = (s % 9) + 1
x = remainder
}
return (x - 1) % 9
}
logCycle([ 9, 6 ])
logCycle([ 9, 9 ])
logCycle([ 9, 9, 9, 9, 9 ])
logCycle([ 9, 129, 993, 91, 9 ])
logCycle([ 9, 10 ])
function logCycle(i) {
log('cycle', i, cycle(i))
}
function log(t, i, o) {
console.log(`${t}(${JSON.stringify(i)}) => ${o}`)
}
注意在 cycle([9, 9])
它是如何返回 0 的,在其他地方它也发生了故障。 cycle
函数采用任意长度的整数数组。所以数组可能有 1000000 个项目,或者只有 2 个。
我预计:
cycle([9, 9]) => 9
cycle([9, 10]) => 1
如何让它正常工作?我如何让它适用于任何一对 min/max 数字,比如如果我想在(包括)5 和 13,或 79 和 5337 之间循环,我如何让它像那样通用?
cycle
函数对结果进行求和和取模,使其理想地在该范围内“循环”。它不是循环迭代,而是“循环求和”,就像一个时钟。
还希望保持解决方案的非递归性,因为 array
中的元素数量可能很大。
显然我一开始误解了问题的某些部分。在阅读了更多评论后,我觉得
- 要遍历的数字可以是任何先前定义的序列,例如从 1 到 9、从 5 到 13 或从 79 到 5337
- (重复)上述序列的总步数由 循环函数所有参数的总和给出。
对于这些要求,以下应该有效:
function defCycle(m,n){
const base=n-m+1,off=m-1; // base: sequence-length, off: offset of sequence
return arr=>(arr.reduce((a,c)=>a+c)%base||base)+off;
};
// run the function on a collection of test data:
const ntest=1000000;
[[1,9],[5,13],[79,5337]]
.forEach(([m,n],cycle)=>{
console.log(`Sequence from ${m} to ${n}:`);
cycle=defCycle(m,n);
[[ 9, 6 ],[ 9, 9 ],[ 9, 9, 9, 9, 9 ],[ 9, 129, 993, 91, 9 ],[ 9, 10 ],[1, 811, 29317, 391, 21],[ntest*(ntest+1)/2]]
.forEach(arr=>console.log(`cycle(${JSON.stringify(arr)}) => ${cycle(arr)}`));
console.log(`cycle([1,2,3,...,${ntest}]) => ${cycle([...Array(ntest)].map((_,i)=>i+1))}`);
});
最后两个测试用例应该产生完全相同的结果:遍历从 1 到 1000000 的序列数组的总和 ( = (1000000*1000001)/2) 应该导致 1
(对于序列:“1...9”)。
defCycle()
函数中的操作发生在这两行中:
base=n-m+1,off=m-1;
base
: 序列元素个
off
: 序列
的偏移量
示例(从 5 到 11 的序列):m=5,n=11
=> base=7,off=4
return arr=>(arr.reduce((a,c)=>a+c)%base||base)+off;
这个returns一个singe-argument-function基于之前计算的base
和off
。计算由两个表达式组成:
[shift]
= (arr.reduce((a,c)=>a+c)
总结了作为参数传递的 arr
的所有元素 - 和
[shift]%base||base
计算实际结果:总数 [shift]
的模数(基数)。每当结果 ==0
它被替换为 base
值。
如果你只需要结果(循环时不需要执行其他操作),那么你可以很容易地使用基础转换来计算它。
function getResult(base, num) {
const str = (parseInt((num-1).toString(base)) + 1).toString()
return str.charAt(str.length - 1)
}
console.log( getResult(9, 6) ) // 6
console.log( getResult(9, 9) ) // 9
console.log( getResult(9, 10) ) // 1
我有这个不工作,像 1 2 3 4 5 6 7 8 9 1 2 3 4 ...
这样的循环,在 1 和 9 之间循环。
const cycle = integers => {
let i = 0
let x = integers[i++]
while (i < integers.length) {
let y = integers[i++]
const s = x + y
const remainder = (s % 9) + 1
x = remainder
}
return (x - 1) % 9
}
logCycle([ 9, 6 ])
logCycle([ 9, 9 ])
logCycle([ 9, 9, 9, 9, 9 ])
logCycle([ 9, 129, 993, 91, 9 ])
logCycle([ 9, 10 ])
function logCycle(i) {
log('cycle', i, cycle(i))
}
function log(t, i, o) {
console.log(`${t}(${JSON.stringify(i)}) => ${o}`)
}
注意在 cycle([9, 9])
它是如何返回 0 的,在其他地方它也发生了故障。 cycle
函数采用任意长度的整数数组。所以数组可能有 1000000 个项目,或者只有 2 个。
我预计:
cycle([9, 9]) => 9
cycle([9, 10]) => 1
如何让它正常工作?我如何让它适用于任何一对 min/max 数字,比如如果我想在(包括)5 和 13,或 79 和 5337 之间循环,我如何让它像那样通用?
cycle
函数对结果进行求和和取模,使其理想地在该范围内“循环”。它不是循环迭代,而是“循环求和”,就像一个时钟。
还希望保持解决方案的非递归性,因为 array
中的元素数量可能很大。
显然我一开始误解了问题的某些部分。在阅读了更多评论后,我觉得
- 要遍历的数字可以是任何先前定义的序列,例如从 1 到 9、从 5 到 13 或从 79 到 5337
- (重复)上述序列的总步数由 循环函数所有参数的总和给出。
对于这些要求,以下应该有效:
function defCycle(m,n){
const base=n-m+1,off=m-1; // base: sequence-length, off: offset of sequence
return arr=>(arr.reduce((a,c)=>a+c)%base||base)+off;
};
// run the function on a collection of test data:
const ntest=1000000;
[[1,9],[5,13],[79,5337]]
.forEach(([m,n],cycle)=>{
console.log(`Sequence from ${m} to ${n}:`);
cycle=defCycle(m,n);
[[ 9, 6 ],[ 9, 9 ],[ 9, 9, 9, 9, 9 ],[ 9, 129, 993, 91, 9 ],[ 9, 10 ],[1, 811, 29317, 391, 21],[ntest*(ntest+1)/2]]
.forEach(arr=>console.log(`cycle(${JSON.stringify(arr)}) => ${cycle(arr)}`));
console.log(`cycle([1,2,3,...,${ntest}]) => ${cycle([...Array(ntest)].map((_,i)=>i+1))}`);
});
最后两个测试用例应该产生完全相同的结果:遍历从 1 到 1000000 的序列数组的总和 ( = (1000000*1000001)/2) 应该导致 1
(对于序列:“1...9”)。
defCycle()
函数中的操作发生在这两行中:
base=n-m+1,off=m-1;
base
: 序列元素个
off
: 序列
的偏移量 示例(从 5 到 11 的序列):m=5,n=11
=>base=7,off=4
return arr=>(arr.reduce((a,c)=>a+c)%base||base)+off;
这个returns一个singe-argument-function基于之前计算的base
和off
。计算由两个表达式组成:[shift]
=(arr.reduce((a,c)=>a+c)
总结了作为参数传递的arr
的所有元素 - 和[shift]%base||base
计算实际结果:总数[shift]
的模数(基数)。每当结果==0
它被替换为base
值。
如果你只需要结果(循环时不需要执行其他操作),那么你可以很容易地使用基础转换来计算它。
function getResult(base, num) {
const str = (parseInt((num-1).toString(base)) + 1).toString()
return str.charAt(str.length - 1)
}
console.log( getResult(9, 6) ) // 6
console.log( getResult(9, 9) ) // 9
console.log( getResult(9, 10) ) // 1