Efficient algorithm for removing items from an array in place

我只是一个虾纸丫 提交于 2021-01-29 22:10:55

问题


I'm looking for an efficient JavaScript utility method that in O(n) will remove a set of items from an array in place. You can assume equality with the === operator will work correctly.

Here is an example signature (written in TypeScript for type clarity)

function deleteItemsFromArray<T>(array: T[], itemsToDelete: T[]) { ... }

My thought is to do this in two passes. The first pass gets the indexes that need to be removed. The second pass then compacts the array by copying backwards from the current index being removed through the next index being removed.

Does anyone have code like this already handy or a more efficient way to do this?

P.S. Please don't point out the filter function as that creates a copy of the array, it does not work in place.


回答1:


Iterate over the array, copying elements that aren't in itemsToDelete to the next destination index in the array. When you delete an element, you don't increment this index.

Finally, reset the length of the array at the end to get rid of the remaining elements at the end.

function deleteItemsFromArray(array, itemsToDelete) {
  let destIndex = 0;
  array.forEach(e => {
    if (!itemsToDelete.includes(e)) {
      array[destIndex++] = e;
    }
  });
  array.length = destIndex;
}

const array = [1, 2, 3, 4, 5, 6, 7];
deleteItemsFromArray(array, [3, 5]);
console.log(array);



回答2:


function deleteItems(array,items){
   let itemsToDelete=0;
   let indexToSwap = array.length-1;
   for(let i = array.length-1,currItem ; i>=0 ; i--){
       if(items.includes(array[i]){
           [array[i] , array[indexToSwap]] = [array[indexToSwap] , array[i]];
           --indexToSwap;
           ++itemsToDelete;
       }
   }

   array.splice(array.length-itemsToDelete,itemsToDelete);
}

This should work, I haven't tested it.
The idea is to swap the elements to delete to the end of the array. You can remove them at the end how I do in my code or you could use too the pop() function every time.




回答3:


It's very, very simple - transform itemsToDelete to a Set. This ensures O(1) lookups. Then walk through the array backwards and remove items with Array#splice. In total, that gives you a linear O(n+m) time complexity:

function deleteItemsFromArray<T>(array: T[], itemsToDelete: T[]) { 
  const setToDelete = new Set(itemsToDelete);

  for (let i = array.length - 1; i >= 0; i--) {
    const item = array[i];

    const shouldBeDeleted = setToDelete.has(item);

    if (shouldBeDeleted) {
      array.splice(i, 1);
    }
  }
}

You can save the conversion step if you just make the function accept a set to begin with and change the signature to:

function deleteItemsFromArray<T>(array: T[], itemsToDelete: Set<T>)

function deleteItemsFromArray(array, itemsToDelete) { 
  for (let i = array.length - 1; i >= 0; i--) {
    const item = array[i];

    const shouldBeDeleted = itemsToDelete.has(item);

    if (shouldBeDeleted) {
      array.splice(i, 1);
    }
  }
}

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
deleteItemsFromArray(
  arr, new Set([1, 3, 5, 7, 8, 9])
)

console.log(arr);



回答4:


Using copyWithin method will be helpful here.

method 1 Traverse from last index to first index, when ever we find the item to remove just copy/move elements to left. Though we will be doing times the copy/move, But still have some unnecessary moving elements.

method 2 Traverse from first index to last index, when ever we find the item to remove, identify the group of elements to copy/move. This will avoid the unnecessary moving elements as in method 1.

function deleteItemsFromArray(array, delete_list) {
  for (let i = array.length - 1; i > -1; i--) {
    if (delete_list.includes(array[i])) {
      array.copyWithin(i, i + 1).pop();
    }
  }
}

// Alternate way, with minimal copy/move group of elements.
function deleteItemsFromArrayAlternate(array, delete_list) {
  let index = -1;
  let count = 0;
  for (let i = 0; i <= array.length; i++) {
    if (delete_list.includes(array[i]) || !(i in array)) {
      if (index > -1) {
        array.copyWithin(index - count + 1, index + 1, i);
      }
      count += 1;
      index = i;
    }
  }
  array.length = array.length - delete_list.length;
}

const array = [9, 12, 3, 4, 5, 6, 7];
deleteItemsFromArray(array, [9, 6, 7]);

console.log(array);


来源:https://stackoverflow.com/questions/62224517/efficient-algorithm-for-removing-items-from-an-array-in-place

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!