JavaScript中更简洁/更好的方法来“修剪”数组?

4
我遇到了一个问题,需要去掉数组的前导0和尾部0(所有元素都是0-9),例如:
  • 对于输入[0, 1, 0, 2, 0],输出应为[1, 0, 2]

  • 对于输入[1, 0, 2],输出应为[1, 0, 2]

  • 对于输入[0, 1, 0, 2, 0, 0],输出应为[1, 0, 2]

基本思路是找到第一个非零数字的索引和最后一个非零数字的索引,然后切割原始数组。
我的方法是将数组转换为字符串并修剪它,然后再将其转换回数组。 trimArray=A=>A.join('').replace(/(^['0']*)|(['0']*$)/g, '').split('').map(a=>a-'0') 还有其他的方法可以做到这一点吗?

4
在回答这个问题之前,请仔细阅读一下。到目前为止已经有好几个答案没有正确理解问题。请注意,不要改变原意。 - Oka
1
function() { return [1,0,2]; } - Blazemonger
5个回答

9
我们可以仅使用数组方法来实现这个功能...
var a = [0, 1, 0, 2, 0, 0];
while(a[0] === 0) {
    a.shift();
}

while(a[a.length - 1] === 0) {
    a.pop();
}
console.log(a)

如果需要保持原始数组不变:(https://jsfiddle.net/4q0un1kp/
function trimZeros(arr)
{
    var result = [...arr];
    while(result[0] === 0) {
        result.shift();
    }

    while(result[result.length - 1] === 0) {
        result.pop();
    }
    return result;
}

var a =  [0, 1, 0, 2, 0, 0];
var b = trimZeros(a);

alert(a);
alert(b);

提醒:这个函数既会 a) 更改数组的值,b) 也会去除 '0' 值以及其他假值。请考虑使用严格的等号比较运算符 === - Oka
@Oka 的观点很有道理,但我感觉它们可能超出了问题的范围。不过,我会更新我的答案,加入一种基于方法的方法。 - Michael Coxon
@Oka OP已经说明了可能的数组值只有0到9这些数字。其他“falsey”值不是问题。 - Blazemonger
@Blazemonger 仍然需要注意边缘情况,因为使用情况会发生变化。 - Oka

1
保持简单,我们可以增加和减少边框线来确定切片的起始和结束位置。
该算法的时间复杂度为O(n),并且具有最小化函数调用的优点。

function trimZeros (array) {
  var front, back, length = array.length;

  if (!length) return [];

  front = 0;
  back = length - 1;

  while (array[front] === 0) front++

  if (front === length) return [];

  while (array[back] === 0) back--;

  return array.slice(front, back + 1);
}

console.log(trimZeros([0, 1, 0, 2, 0, 0]))

或者,您可以将其组成一个方法,该方法接受功能测试,从而创建更通用的版本。此版本具有边界检查(以防尝试修剪未定义)。

if (!Array.prototype.trim) {
  Array.prototype.trim = function (test) {
    var start, end, length = this.length;

    if (!length) return [];

    start = 0;
    end = length - 1;

    while (start < length && test(this[start], start)) start++;

    if (start === end) return [];

    while (end >= 0 && test(this[end], end)) end--;

    return this.slice(start, end + 1);
  }
}

console.log([0, 0, 1, 0, 2, 0, 0, 0].trim(e => e === 0));


1
这比被接受的答案更加简洁和快速。 - Daniel Beck

0
你可以使用 for 循环来实现它:

function trimArray(arr) {
  var lastIndex = arr.length - 1;
  var low = {
      found: false,
      index: 0
    },
    high = {
      found: false,
      index: arr.length
    };

  for (var i = 0; i < arr.length; i++) {
    if (!low.found && arr[i] !== 0) {
      low.index = i;
      low.found = true;
    }
    if (!high.found && arr[lastIndex - i] !== 0) {
      high.index = (lastIndex - i) + 1;
      high.found = true;
    }
    if (high.found && low.found) break;
  }

  if (high.found && low.found) {
    var highCut = -(arr.length - high.index)
    return arr.slice(low.index, highCut ? highCut : arr.length);
  } else {
    return [];
  }
}

var testCases = [
    [0],
    [0, 0],
    [0, 1],
    [0, 1, 0],
    [0, 1, 0, 1, 0],
    [0, 1, 0, 1],
    [1, 0, 1, 0],
    [1, 0, 1]
  ];

var result = testCases.map(trimArray);
results.innerHTML = JSON.stringify(result, null);
<pre id="results"></pre>


0
我想出了这个递归解决方案,以删除数组开头或结尾的每个零。
var array = [0,0,1,2,0,5,0,0,0,0];

// function to remove all zeros
function removeZeros(array){

  if(array[0] === 0 && array[array.length-1] === 0){
    return removeZeros(array.slice(1,array.length-1));
  }
  else if(array[0] === 0){
    array.shift();
    return removeZeros(array);
  }
  else if(array[array.length-1] === 0){
    array.pop();
    return removeZeros(array);
  }
  else{
    return array;
  }
}

console.log(removeZeros(array)); //[1, 2, 0, 5]

希望它有所帮助


-2
var arr = [0, 0, 2, 3, 0, 0];

while (arr[0] === 0) {
    arr.shift();
}
while (arr[arr.length-1] === 0) {
    arr.pop();
}

这将仅从两端修剪一个零。 - JJJ
据我所知,@Juhana,这是作者需要的内容:“修剪数组的前导0和尾随0”。 - Suleiman
不,"0s"中的"s"表示复数。"[all] first zeros"和"[all] last zeros"。请看问题中的第三个例子。 - JJJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接