【问题标题】:How to filter an array without another array javascript如何在没有另一个数组javascript的情况下过滤数组
【发布时间】:2019-12-27 02:15:33
【问题描述】:

到目前为止,我尝试了这个,但它返回未过滤的数组:

function filterRangeInPlace(array, min, max) {
  array = array.filter(item => (item >= min && item <= max));
  console.log(array);
}

let arr = [5, 3, 8, 1];

filterRangeInPlace(arr, 1, 4);

console.log(arr);

【问题讨论】:

  • .filter() always 创建一个新数组。您的代码不起作用,因为在函数中对 array 的赋值是对参数的赋值,而 JavaScript 是按值传递的语言。
  • 要真正实现问题标题的要求,您必须编写一个函数来“粉碎”数组以消除过滤掉的条目。
  • 函数.filter()不像for循环,这个函数实际上对数组实体应用过滤器并返回一个新的过滤数组,它不会对实际数组进行更改就像for 循环,所以当你需要过滤任何数组时,你必须需要一个变量来保存过滤后的数组结果,或者只使用for 循环并从数组中删除影响原始数组元素的不满意条目

标签: javascript arrays filter


【解决方案1】:

如果在不创建另一个数组的情况下就地进行过滤实际上很重要,那么您必须采用老式的方法并使用两个索引遍历数组,并在此过程中复制值。每次遇到未通过过滤器测试的元素时,都会增加一个索引,但不会增加另一个。最后,将数组 .length 重置为尾随索引:

function filterInPlace(array, fn) {
  let from = 0, to = 0;
  while (from < array.length) {
    if (fn(array[from])) {
      array[to] = array[from];
      to++;
    }
    from++;
  }
  array.length = to;
}

这具有 O(n) 的优势,只需遍历数组一次,而涉及 .splice() 的解决方案是 O(n2)。

要进行“范围检查”,您可以编写另一个函数来创建一个给定最小值和最大值的过滤谓词:

function rangePredicate(min, max) {
  return n => n >= min && n <= max;
}

然后你可以将它的返回值传递给过滤函数:

var arr = [1, 2, 3, ... ];
filterInPlace(arr, rangePredicate(0, 10));

【讨论】:

  • 感谢您的精彩回答,这就是我正在寻找的 - 过滤数组的快速且廉价(用于内存)的方法。
  • 请您添加您的fn 版本以确保答案的完整性?谢谢
  • @RobertHovhannisyan 好吧,fn 可以是任何函数,就像您传递给 .filter() 的函数一样。如果它返回true,则该值包含在最终数组中,否则不包含。
  • @RobertHovhannisyan 回答已扩展。
  • 哦,太好了。现在一切都清楚了。再次感谢您!
【解决方案2】:

您需要返回新过滤的数组并将其分配给一个变量(例如arr本身):

function filterRangeInPlace(array, min, max){
  return array.filter(item => (item >= min && item <= max));
}

let arr = [5, 3, 8, 1];

arr = filterRangeInPlace(arr, 1, 4);

console.log(arr);

【讨论】:

  • 这当然可行,但它不满足问题的“没有另一个数组”部分。
  • 这是过滤数组的一种非常聪明的方法,但在这种情况下我同意@Pointy。不过还是谢谢你的好回答!
【解决方案3】:

返回值并将其设置为等于自身。

function filterRangeInPlace(array, min, max) {
  return array.filter(item => (item >= min && item <= max));
}

let arr = [5, 3, 8, 1];

arr = filterRangeInPlace(arr, 1, 4);

console.log(arr);

或者您当然可以完全省略该函数:

let arr = [5, 3, 8, 1];

arr = arr.filter(item => (item >= min && item <= max));

console.log(arr);

【讨论】:

  • 那个有趣而简短的答案。感谢您的努力!
【解决方案4】:

您不能为此使用.filter(),因为它返回一个新数组而不是修改原始数组。您可以自己循环遍历数组,删除不符合条件的元素。

您需要按索引的降序执行循环,因为删除一个元素会将所有剩余元素的索引向下移动,如果按升序执行,您最终会跳过下一个元素。这也意味着你不能使用像.forEach() 这样的内置函数。

function filterRangeInPlace(array, min, max) {
  for (let i = array.length-1; i >= 0; i--) {
    if (array[i] < min || array[i] > max) {
      array.splice(i, 1);
    }
  }
}

let arr = [5, 3, 8, 1];
filterRangeInPlace(arr, 1, 4);
console.log(arr);

【讨论】:

  • 如果你使用array.splice(),你会这样做。我想你可以继续减少i
  • 但是你不能使用forEach,它不提供备份方式。
  • 我会按照我在回答中写的去做,因为在我脑海中的某个地方,我仍然是 pdp-11 上的 C 程序员。
  • 这是一个很棒的解决方案。非常感谢您的代码!
猜你喜欢
  • 2022-12-22
  • 2010-11-25
  • 2023-02-11
  • 1970-01-01
  • 2013-09-24
  • 2015-10-18
  • 2021-07-29
  • 2018-01-06
相关资源
最近更新 更多