【问题标题】:Weird bug in Javascript splice methodJavascript拼接方法中的奇怪错误
【发布时间】:2019-11-11 14:49:30
【问题描述】:

我有一个包含“零”的数组,我想移动所有 “零”到数组的最后一个索引。

预期的输出是:

[1,2,3,0,0,0,0]

但是我得到了:

[1,2,0,3,0,0,0]

let a = [0, 1, 2, 0, 0, 3, 0];
let count = 0;
let len = a.length;

for (i = 0; i < len; i++) {
  if (a[i] == 0) {
    count = count + 1;
    a.splice(i, 1);
  }
}

for (j = 0; j < count; j++) {
  a.push(0);
}

console.log(a);

【问题讨论】:

  • 标题似乎暗示您在原生 JavaScript 方法中发现了一个错误。压制那个念头。说服自己不是那个方法有错误,而是你的代码。

标签: javascript algorithm sorting array-algorithms


【解决方案1】:

当您从数组中删除项目时,所有元素都会下移一位。当您推进索引 (i++) 时,您会跳过数组中向下移动的项,该项恰好在数组中连续为零。

解决方案:向后执行 for next 循环,它会起作用。

【讨论】:

    【解决方案2】:

    您可以在每次使用拼接时添加i--;len--;

    let a = [0, 1, 2, 0, 0, 3, 0];
    let count = 0;
    let len = a.length;
    
    for (i = 0; i < len; i++) {
      if (a[i] == 0) {
        count = count + 1;
        a.splice(i, 1);
        i--; len--;
      }
    }
    
    for (j = 0; j < count; j++) {
      a.push(0);
    }
    
    console.log(a);
    

    这是因为当你拼接1个元素时,数组的key会下移一位,所以你要检查的下一个元素的key和你刚刚移除的那个key是一样的。 len 也用len--; 更正,因为我们刚刚删除了一个元素。

    虽然此答案是使用原始计划执行此操作的正确方法,但它是一种修复。您的问题是您循环遍历一个数组,并且该数组在循环期间丢失了元素,通常在这些情况下正确的方法是向后循环。这样,在循环期间可能会更改其密钥的元素就是我们已经检查过的元素。

    【讨论】:

      【解决方案3】:

      你可以用Array.prototype.sort()做的更简单:

      const array = [0, 1, 2, 0, 0, 3, 0];
      const sortedArray = array.sort((a, b) => {
        if (a === 0) {
          return 1;
        }
        if (b === 0) {
          return -1;
        }
        return a - b;
      });
      
      console.log(sortedArray);

      【讨论】:

      • 既然我们可以在 O(n) 中轻松完成,为什么还要在 O(n log n) 中完成?
      • @גלעדברקן 我认为我们还需要对数组进行排序。
      【解决方案4】:

      因为 splice 改变了数组的长度,所以可以从数组的末尾开始迭代,将找到的值直接拼接到最后一个索引。

      使用这种方法,您只需要一个循环。

      var a = [0, 1, 2, 0, 0, 3, 0],
          i = a.length;
      
      while (i--) {
          if (a[i] === 0) {
              a.splice(a.length, 0, ...a.splice(i, 1));
          }
      }
      
      console.log(a);

      没有拼接的更短的方法 - 从零开始。

      var a = [0, 1, 2, 0, 0, 3, 0],
          i, j = 0;
      
      for (i = 0; i < a.length; i++) {
          if (a[i] !== 0) {
              [a[j], a[i]] = [a[i], a[j]]; // swap
              j++;
          }        
      }
      
      console.log(a);

      【讨论】:

        【解决方案5】:

        在for循环中,当你拼接数组时,数组和它的长度都会改变。

        为此,您必须通过减去 1 来修复 for 循环中的 i

          i++;
        

        并通过减1来固定长度或重新获取长度

        let a = [0, 1, 2, 0, 0, 3, 0];
        let count = 0;
        let len = a.length;
        
        for (i = 0; i < len; i++) {
          if (a[i] == 0) {
            count = count + 1;
            a.splice(i, 1);
            len = a.length;
            i--;
          }
        }
        
        for (j = 0; j < count; j++) {
          a.push(0);
        }
        
        console.log(a);

        【讨论】:

          【解决方案6】:

          请注意,每个splice的调用通常具有O(n) complexity。有很多方法可以通过单次 O(n) 迭代更有效地实现您想要的结果一个数量级。这是一个:

          let a = [0, 1, 2, 0, 0, 3, 0]
          
          for (let i=0, j=0; j<a.length; j++)
            if (a[j] && i != j)
              [a[i++], a[j]] = [a[j], 0]
          
          console.log(a)

          【讨论】:

            【解决方案7】:

            不是一遍又一遍地拼接数组,这里有一种不同的方法:

            let a = [0, 1, 2, 0, 0, 3, 0];
            // create some more (random) data
            for (let i = a.length; i < 30; ++i)
              a[i] = Math.floor(Math.random() * Math.random() * 10);
            console.log(""+a);
            
            let i = 0, j = 0, len = a.length;
            // move non-0 values to the front
            while (i < len) {
              if (a[i] !== 0) {
                a[j++] = a[i];
              }
              ++i;
            }
            // fill the end of the list with 0
            while (j < len) a[j++] = 0;
            
            console.log(""+a);

            【讨论】:

              猜你喜欢
              • 2015-10-24
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-10-06
              • 2014-03-14
              • 2012-07-23
              • 2011-05-14
              相关资源
              最近更新 更多