使用splice()更改数组

时间:2018-05-16 18:15:02

标签: javascript arrays

我正在尝试编写一个函数,给定一个数组和n,返回数组重复不超过n次的元素。我无法改变数组的顺序。

以下是我到目前为止的代码。令我困惑的是,它适用于给定数组中的大多数元素,但不适用于其他元素。我试图找到代码不起作用的元素的押韵或原因。

function deleteNth(arr,n){
  arr.forEach(function (item, index) {
    var count = 0;
    for (var i = 0; i < arr.length; i++) {
      if (arr[i] === item) {
        count++;
      while (count > n) {
       var remove = arr.lastIndexOf(item);
       arr.splice(remove, 1);
       count--;
      }
    }
  }
});
  return arr;
}


var x = deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 
35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 
35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 
2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2);

console.log(x);

目前返回此...

[7, 26, 21, 41, 43, 2, 26, 24, 10, 10, 10, 24, 35, 35, 43, 41, 7, 21, 
41, 2, 43, 28]

但我应该得到这个......

[7, 26, 21, 41, 43, 2, 26, 24, 10, 10, 24, 35, 35, 43, 41, 7, 21, 2, 
28]

对于我出错的地方的任何见解都将深表感谢。

6 个答案:

答案 0 :(得分:4)

你放置while循环的逻辑是错误的,你需要把它放在for循环之外。

&#13;
&#13;
function deleteNth(arr, n) {
  arr.forEach(function(item, index) {
    var count = 0;
    for (var i = 0; i < arr.length; i++) {
      if (arr[i] === item) {
        count++;        
      }
    }
    while (count > n) {
      var remove = arr.lastIndexOf(item);
      arr.splice(remove, 1);
      count--;
    }
  });
  return arr;
}


var x = deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35,
  35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41,
  35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7,
  2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10
], 2);

console.log(x);
&#13;
&#13;
&#13;

为什么呢?因为当你进行循环并从中移除东西时,你会把东西放回去。因此,当你有两个并排的物品时,你将第一个物品移开,第二个物品向下移动一个点以填充刚刚移除的物品。 i不会更改,因此您不会检查刚填补空白的项目。

我该怎么办?我会跟踪这些项目,如果我没有超过最大值附加它。

&#13;
&#13;
function cleanUp (arr, max) {
  const cnts = {}  // keep track of what we find
  return arr.reduce((a, i) => { // loop over the array index by index
    cnts[i] = (cnts[i] || 0) + 1;  // mark that I seen the number
    if (cnts[i] <= max) {  // check to see if we are under the max
      a.push(i)  //if we are, add it to an arry
    }
    return a  // return the array for reduce
  }, [])
}
console.log(cleanUp([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 
35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 
35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 
2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2))
&#13;
&#13;
&#13;

答案 1 :(得分:2)

对于快速变异版本,您可以使用单个while循环,用于计算项目的哈希表以及在拼接发生时调整索引。

&#13;
&#13;
function deleteNth(array, n) {
    var counter = Object.create(null),
        i = 0, v;

    while (i < array.length) {
        v = array[i];
        if (!counter[v]) {
            counter[v] = 0;
        }
        if (++counter[v] > n) {
            array.splice(i, 1);
            continue;
        }
        i++;
    }
    return array;
}

console.log(deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2));
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

更好的方法是使用过滤器并返回一个新数组。

&#13;
&#13;
function deleteNth(array, n) {
    var counter = Object.create(null);
    return array.filter(v => (counter[v] = (counter[v] || 0) + 1) <= n);
}

console.log(deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2));
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

答案 2 :(得分:2)

此代码有效:

&#13;
&#13;
function deleteNth(arr,n){
     var rem = new Array(), new_arr = new Array();
     arr.forEach(function (item, index) {
        if(!rem[item]) rem[item]=0;
     	if(rem[item]<n){
        	new_arr.push(item);
        	rem[item]++;
        }
     });
    return new_arr;
   }

console.log(deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2));
&#13;
&#13;
&#13;

答案 3 :(得分:2)

你的所有代码都是真的。只需将while带出for循环。

function deleteNth(arr, n) {
  arr.forEach(function(item, index) {
    var count = 0;
    for (var i = 0; i < arr.length; i++) {
      if (arr[i] === item) {
        count++;
      }
    }
    while (count > n) {
          var remove = arr.lastIndexOf(item);
          arr.splice(remove, 1);
          count--;
        }
  });
  return arr;
}


var x = deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35,
  35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41,
  35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7,
  2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10
], 2);

console.log(x);

答案 4 :(得分:2)

我喜欢Nina的过滤器(也可能表现得更好)但你也可以使用reduce:

function deleteNth(arr,n){
  return arr.reduce(
    ([result,map],item)=>{
      const count = (map.get(item)||0)+1;
      return [
        //do not add if more than n of this item have been added already
        (count<=n)?result.concat(item):result,
        map.set(item,count)//set the new count for this item and return map
      ]
    },
    [[],new Map()]//initial value for result and map
  )[0];
}

以下是使用过滤器和Map的示例:

function deleteNth(arr,n){
  const map = new Map();
  return arr.filter(
    item=>{
      const count = (map.get(item)||0)+1;
      map.set(item,count);
      return (count<=n);
    }
  );
}
console.log(deleteNth([1,2,3,2,4,2,5], 2));

答案 5 :(得分:2)

如果你真的想这样做,那么这个答案不适合你。 (我认为有很好的理由使用不可变数据,但如果你想改变,其他答案之一就应该这样做。

这是一个解决方案,可以随时查看每个项目的计数,并过滤掉我们经常看到的项目:

const deleteNth = (arr, n) => {
  const found = new Map()
  return arr.filter(val => {
    found.set(val, (found.get(val) || 0) + 1)
    return found.get(val) <= n
  })
}

const result = deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2)

console.log(result)

另一个注意事项:如果您选择,它可能会提供更好的API:

deleteNth = (n) => (arr) => { /* ... */ }

这样你就可以只传递重复计数并返回一个过滤数组的新函数。

(另外,对于删除第n个之后所有重复值的内容,这听起来不是一个好名字。)