javascript - 如何用数组实现轮播

标签 javascript algorithm

我有一个代表虚拟轮播的项目数组。

const carousel = ['a','b','c','d','e'];
let currentIndex = 0;

function move (amount) {
   const l = items.length;  // in case carousel size changes

   // need to update currentIndex

   return carousel[currentIndex];

}

currentIndex == 0 时向左移动和当 currentIndex == length-1 时向右移动有什么干净或聪明的方法?

我以前考虑过这个问题,但从来没有想出任何非常聪明或简洁的东西。

最佳答案

简答

实现 circular array通过modular arithmetic .给定移动距离,计算相应的索引:

// put distance in the range {-len+1, -len+2, ..., -1, 0, 1, ..., len-2, len-1}
distance = distance % len
// add an extra len to ensure `distance+len` is non-negative
new_index = (index + distance + len) % len

长答案

使用modular arithmetic很像您阅读典型模拟时钟的方式。前提是两个整数相加,除以一个整数,保留余数。例如,13 = 3 (mod 10)因为131*10 + 330*10 + 3 .

但为什么我们选择安排313像我们一样?为了回答这个问题,我们考虑 Euclidean division algorithm (EDA) .它表示两个整数 ab存在唯一整数 qr这样

a = b*q + r

0 ≤ r < b .这比您想象的更强大:它允许我们“以模数 n 工作”。

也就是说,我们可以说 a = b (mod n) iff 存在唯一整数 q1 , r1 , q2 , 和 r2这样

a = n * q1 + r1,   0 ≤ r1 < n
b = n * q2 + r2,   0 ≤ r2 < n

r1等于 r2 .我们调用r1r2 “余数”。

回到前面的例子,我们现在知道为什么13 = 3 (mod 10)了。 . EDA 说 13 = 1*10 + 313是唯一的qr满足必要的约束;按照类似的逻辑,3 = 0*10 + 3 .由于余数相等,我们说 133在“working mod 10”时是相等的。

幸运的是,JavaScript 实现了一个 modulo operator天生的。不幸的是,我们需要注意一个怪癖,即模运算符保留其操作数的符号。这会给你一些结果,比如 -6 % 5 == -1-20 % 7 == -6 .虽然完全有效的数学陈述(检查原因),但在涉及数组索引时这对我们没有帮助。

引理 1: a + n = a (mod n)
引理 2: -1 = n-1 (mod n)
引理 3: -a = n-a (mod n)

克服这个问题的方法是“欺骗”JavaScript 使用正确的符号。假设我们有一个长度为 len 的数组和当前索引 index ;我们想将索引移动一段距离 d :

// put `d` within the range {-len+1, -len+2, ..., -2, -1, -0}
d = d % len
// add an extra len to ensure `d+len` is non-negative
new_index = (index + d + len) % len

我们首先将 d{-len+1, -len+2, ..., -2, -1, -0} 范围内.接下来,我们添加一个额外的 len确保我们移动的距离在 {1, 2, ..., len-1, len} 范围内,从而确保 % 的结果操作有一个积极的迹象。我们知道这是有效的,因为 (-a+b) + a = b (mod a) .然后我们将新索引设置为 index + d + len (mod len) .

更详细的实现:

class Carousel {
  // assumes `arr` is non-empty
  constructor (arr, index = 0) {
    this.arr = arr
    this.index = index % arr.length
  }
  // `distance` is an integer (...-2, -1, 0, 1, 2, ...)
  move (distance) {
    let len = this.arr.length
    distance = distance % len
    let new_index = (this.index + distance + len) % len
    this.index = new_index
    return this.arr[this.index]
  }
}

// usage:
let c = new Carousel(['a','b','c','d','e'], 1) // position pointer set at 'b'
c.move(-1)  // returns 'a' as (1 + -1 + 5) % 5 == 5 % 5 == 0
c.move(-1)  // returns 'e' as (0 + -1 + 5) % 5 == 4 % 5 == 4
c.move(21)  // returns 'a' as (4 + 21 + 5) % 5 == 30 % 5 == 0

关于javascript - 如何用数组实现轮播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41274905/

相关文章:

javascript - 如何获取有关随机智能合约地址的数据。例如创建日期、链、持有者(持有多少个钱包)

javascript - Node 和MySQL-connection.query内部的connection.query-无法访问对象属性

javascript - 使用jquery和php更新img

使用 Sethi-Ullman 算法的表达式代码生成器

algorithm - 动态规划与贪心算法有何不同?

javascript - 在贪吃蛇游戏中,如何移动具有不同棋子的蛇?

javascript - JS .children 返回一个对象,想要一个数组(ES6)

javascript - mapbox gl js - 未捕获的类型错误 : Cannot read property 'classList' of null

algorithm - 动态规划计算子集和(背包)中子集解的个数

algorithm - 求一个递归算法的复杂度