繁体   English   中英

使用splice()更改数组

[英]Changing an array in place using splice()

我正在尝试编写一个函数,给定一个数组和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]

任何洞察我出错的地方都将深表感谢。

放置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); 

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

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

 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)) 

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

 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)); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

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

 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)); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

此代码有效:

 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)); 

你的所有代码都是真的。 只要把那whilefor循环。

 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); 

我喜欢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));

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

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

 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个之后所有值重复的内容,这听起来不是一个好名字。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM