fezaoduke / fe-practice-hard

晚练课
69 stars 6 forks source link

第 81 期(数据结构-数组):数组项的互换和移动 #84

Open wingmeng opened 5 years ago

wingmeng commented 5 years ago

数组是一种由有序的元素序列组成的集合,每个元素在数组中有一个位置,以数字表示,称为索引。 那么如何对数组项的位置进行移动操作?如何实现两个数组项的位置互换?

思路:

数组项的位置移动本质上是相邻数组项的位置互换(数组边界的情况除外),例如下面的数组:

['A', 'B', 'C', 'D'];  // 原数组
['A', 'C', 'B', 'D'];  // 将 C 向前移动一位

我们将 C 向前移动 1 位,本质上就是 B 和 C 互换了位置。那么如何实现位置互换?可以使用临时变量存储 B,然后从数组中删除 B,再将 B 插入到 C 的后面;或者用 ES6 的结构赋值,临时变量都省了,非常方便。 下面我们来看下具体实现。

/**
 * 交换数组项
 * @param {array} arr - 源数组
 * @param {number} srcIdx - 要交互位置的源数组项索引
 * @param {number} targetIdx - 目标位置索引
 */
function swapArrItem(arr, srcIdx, targetIdx) {
  if (!Array.isArray(arr)) {
    throw Error(`\`${arr}\` is not a array`);
  }

  if (isNaN(srcIdx) || isNaN(targetIdx)) {
    throw Error(`index is not a number`);
  }

  let len = arr.length - 1;

  // 边界情况判断
  srcIdx = srcIdx < 0 ? 0 : srcIdx;
  srcIdx = srcIdx > len ? len : srcIdx;
  targetIdx = targetIdx < 0 ? 0 : targetIdx;
  targetIdx = targetIdx > len ? len : targetIdx;

  arr = [...arr];
  [arr[srcIdx], arr[targetIdx]] = [arr[targetIdx], arr[srcIdx]];  // 解构赋值

  return arr;
}

/**
 * 移动数组项
 * @param {array} arr - 源数组
 * @param {number} idx - 要移动的源数组项索引
 * @param {string} method - 移动方式:
      1. first - 移动到数组最前
      2. last - 移动到数组最后
      3. forward - 向前移动1位
      4. backward - 向后移动1位
 */
function moveArrItem(arr, idx, method) {
  const _toBoundary = (arr1, idx, handle) => {
    let temp = arr1.splice(idx, 1)[0];

    arr1[handle](temp);
    return arr1;
  };

  if (!Array.isArray(arr)) {
    throw Error(`\`${arr}\` is not a array`);
  }

  arr = [...arr];

  switch(method) {
    case 'first':
      return _toBoundary(arr, idx, 'unshift');
    case 'last':
      return _toBoundary(arr, idx, 'push');
    case 'forward':
      return swapArrItem(arr, idx, idx - 1);
    case 'backward':
      return swapArrItem(arr, idx, idx + 1);
    default:
      throw Error(`${method} is not a available parameter`);
  }
}

测试用例:

let testArr = [0, 1, 2, 3, 4, 5];

console.log('原数组', testArr);
console.log('交换下标1和2项的位置', swapArrItem(testArr, 1, 2));
console.log('交换下标0和3项的位置', swapArrItem(testArr, 0, 3));
console.log('交换下标-5和9项的位置(越界测试)', swapArrItem(testArr, -5, 9));

console.log('将下标2项移动到最前', moveArrItem(testArr, 2, 'first'));
console.log('将下标2项移动到最后', moveArrItem(testArr, 2, 'last'));
console.log('将下标2项向前移动1位', moveArrItem(testArr, 2, 'forward'));
console.log('将下标2项向后移动1位', moveArrItem(testArr, 2, 'backward'));