【问题标题】:Why if statements blocks in while loop?为什么if语句会在while循环中阻塞?
【发布时间】:2019-06-11 11:24:15
【问题描述】:

我有一个数字数组,其中包含一堆重复项。我需要摆脱它们,所以我把代码:

  let dup = arr.filter((elem, pos)=> arr.indexOf(elem) !== pos);
  // dup Array contains the duplicate numbers
  arr = arr.filter((elem, pos)=> arr.indexOf(elem) == pos);
  //arr contains the whole array with duplicates
  let i = 0;
  let j = 0;
  while(i<arr.length){
    while(j<dup.length){
      if(arr[i] == dup[j]){
        arr.splice(i, 1);
        //the splice method resets the decrease the index of the array so
        i--;
      };
      j++;
    };
    i++
  }

问题是 if 在第一次匹配后没有运行。所以数组splice 是它找到并停止的第一个重复项。我该如何解决?

【问题讨论】:

  • 我很困惑。在您的第二个 filter 之后,该数组已经没有重复项。 (并且不需要第一个filter。)
  • @ScottSauyet 我认为他想摆脱两个重复的数字。他可以用arr.filter(x=&gt; dup.indexOf(x) &lt; 0) 做到这一点。但他正试图通过一些复杂的循环来删除它
  • @James,哦,好吧,这很有道理。
  • @James 您的回答似乎简单易行。我将用那一行替换我所有的循环。谢谢

标签: javascript arrays loops if-statement


【解决方案1】:

来自Get all unique values in a JavaScript array (remove duplicates)

const myArray = ['a', 1, 'a', 2, '1'];

const unique = [...new Set(myArray)]; 

// output ["a", 1, 2, "1"]

或作为函数

const unique = [...new Set(myArray)]

【讨论】:

  • 这并没有回答他为什么他的 IF 只命中一次的问题。
  • 公平点@James,希望这个建议可以被 OP 使用,如果它得到预期的结果。我发现很难用多个 while 和 if 语句来调试他的实际代码
  • 是的,这令人困惑。我认为他也想删除顺便说一句重复的项目,因为在第二个过滤器之后,他的arr 中已经有了独特的项目。所以在你的例子中,他只想要 [2]
【解决方案2】:

问题是你永远不会重置j。您需要将其移动到 while (i ...) 循环内。

let arr = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
console.log('arr', arr)

let dup = arr.filter((elem, pos)=> arr.indexOf(elem) !== pos);

console.log('dup', dup)

arr = arr.filter((elem, pos)=> arr.indexOf(elem) == pos)
console.log('new arr', arr)


let i = 0;
while(i<arr.length){
  let j = 0;
  while(j<dup.length){
    if(arr[i] == dup[j]){
      arr.splice(i, 1);
      i--;
    };
    j++;
  };
  i++
}

console.log('final arr', arr)

但是有更简单的方法可以做到这一点。

更新

我因提及更简单的方法而没有展示一种方法而受到警告。这是获得相同结果的另一种方法:

const singletons = (
  xs,
  dups = xs .filter ((x, i) => arr .indexOf (x) !== i)
) => xs .filter (x => dups .indexOf (x) < 0)

let arr = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]

console .log (
  singletons (arr)
)

此版本不会修改您的原始数组,只是返回一个仅包含单例元素(在原始列表中仅出现一次的元素)的新数组。

说明

singletons 是一个函数,它采用某种元素类型的数组并返回另一个相同类型的数组。因为该类型不是特定的,所以我使用了一个非特定的名称;一个相当强大的约定使这个xss 指出它是复数形式(即它们的数组。)

dups 是在原始元素中重复的元素数组。尽管我将它作为默认参数包含在内,但我们可以像这样在函数体中轻松创建它:

const singletons = (xs) => {
  const dups = xs .filter ((x, i) => arr .indexOf (x) !== i)
  return xs .filter (x => dups .indexOf (x) < 0)
}

我没有这样做的唯一原因是我可能过于喜欢单个表达式体,因此避免了 {-} 对和 return 语句。但是这两种方法之间并没有真正的区别,除了我提出的那个方法恰好做了一些我永远不会指望的额外工作:如果你提供第二个参数,一个值数组,那么,而不是删除重复项,它从你的数组中删除所有那些也在第二个元素中的元素,隐约让人想起一组差异函数。

与您的方法相比,它的主要优点是它是非破坏性的。它不会改变您的原始数据。它也没有赋值,除了在默认参数中,所以在状态管理中没有混淆。 (“我在哪里放let j == 0?”在这里不是一个有意义的问题。)这使它感觉更健壮。

【讨论】:

  • 你能告诉我singletons 是什么类型吗?括号是干什么用的。以及为什么 xs,dups。你能告诉我在哪里了解它吗?
  • @EyePatch:我添加了一个解释部分。短版:这是一种相当标准的函数式编程方法。
  • 我没有意识到这是一个函数,因为括号内有一个赋值。我不知道这样的事情是可能的。
  • @EyePatch: Default Parameters 对于这类事情非常有用。
【解决方案3】:

需要在第一个while循环中设置j=0,否则只会在第二个while循环中运行一次。

另外,如果我是你,我会使用 for 循环(特别是 array.forEach())而不是 while,因为它们已经计算了元素的数量。

我的解决方案是这样的:

arr.forEach((e, i) => {
    dup.forEach((f, j) => {
        if(e==f){
            arr.splice(i, 1);
        }
    })
});

希望它对你有用。

编辑:

从 James 对原始问题的评论中窃取。 无论如何,Javascript 已经提供了一种简单的方法来做到这一点:

arr.filter(x=> dup.indexOf(x) < 0)

【讨论】:

  • 是的。实际上我一开始尝试了 whit for 循环,但这是同样的问题,所以我切换到 while lopps 希望它能解决它。
  • 这里的好处是你不需要定义你正在经历的变量,它都被处理了。可能是最短和最可靠的方法。 While-loops 很棘手,有时它们不会像您预期的那样终止,或者在您的情况下是循环。
  • 效果很好。但是为了解决我删除数组中两个重复项的问题,我更喜欢评论中的答案,而不是我的问题,即单行代码
猜你喜欢
  • 2016-04-21
  • 2015-05-19
  • 2015-06-21
  • 2021-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多