【问题标题】:deleting duplicates on sorted array删除排序数组上的重复项
【发布时间】:2012-03-10 10:56:03
【问题描述】:

万一你错过了,问题是关于删除 sorted 数组上的重复项。可以应用非常快速的算法(与未排序的数组相比)来删除重复项。

  • 如果您已经知道如何在 SORTED 数组上删除重复项,则可以跳过此步骤

示例:

var out=[];
for(var i=0,len=arr.length-1;i<len;i++){
    if(arr[i]!==arr[i+1]){
        out.push(arr[i]);
    }
}
out.push(arr[i]);

看到了吗?速度非常快。我会尽力解释刚刚发生的事情。

排序后的数组*可能如下所示:

arr=[0,1,1,2,2,3,4,5,5,6,7,7,8,9,9,9];

*排序可以是 ASC 或 DESC,也可以是其他奇怪的方法,但重要的是每个重复的项目都彼此相邻。

我们停在array.length-1,因为我们没有任何东西要检查

然后我们不顾一切地添加了最后一个元素,因为:

案例A:

... ,9,9,9];//we have dup(s) on the left of the last element

案例 B:

... ,7,9,10];//we don't have dup(s) on the left of the last element

如果您真的了解发生了什么,您就会知道我们没有在案例 A 上添加任何 9。因此,无论我们是在案例 A 上还是在案例 A 上,我们都希望添加最后一个元素B.


问题:

也就是说,我也想做同样的事情,但在以下情况下忽略 undefined 值:

var arr=[];arr[99]=1;//0 through 98 are undefined, but do NOT hold the undefined value

我想删除那些。如果我有一些真实的undefined 值,则不应删除这些值。

我糟糕的尝试是这个:

var out=[];
for (var i=0,len=arr.length; i < len - 1;) {
  var x = false;
  var y = false;

  for (var j = i, jo; j < len - 1; j++) {
    if (j in arr) {
      x = true;
      jo = arr[j];
      i = j + 1;
      break;
    }
  }
  if (x == false) {
    break;
  }

  for (var u = i, yo; u < len - 1; u++) {
    if (u in arr) {
      y = true;
      yo = arr[u];
      i = u + 1;
      break;
    }
  }
  if (y == false) {
    out.push(jo);
    break;
  }

  if (jo !== yo) {
    out.push(jo);
  }
}
out.push(arr[len - 1]);

我真的迷路了,感谢任何帮助

【问题讨论】:

  • 你想要什么行为?你只是想忽略数组中不存在的部分,还是什么?
  • @peter 我想删除 dups,即使之间有未定义
  • 我认为您应该将初始数组打包到一个临时数组中(删除未定义的值)并使用它进行重复检查..

标签: javascript arrays duplicates duplicate-removal sorted


【解决方案1】:

使用 .filter() 的现代单线

arr.filter((e, i, a) =&gt; e !== a[i - 1]);

我对这里其他答案的复杂性感到非常惊讶,即使是那些使用.filter()的答案

即使使用没有箭头函数的老式 ES5 语法:

arr.filter(function (e, i, a) { return e !== a[i - 1] });

例子:

let a = [0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 9];

let b = arr.filter((e, i, a) => e !== a[i - 1]);

console.log(b); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

如果您需要就地改变数组,那么只需使用:

arr = arr.filter((e, i, a) => e !== a[i - 1]);

我个人建议不要使用此处其他答案中的复杂解决方案。

【讨论】:

    【解决方案2】:

    首先,我不完全确定您的原始代码是否符合犹太教规。在我看来,当原始列表为空时它可能无法正常工作,因为无论如何您都会尝试推送最后一个元素。最好写成:

    var out = [];
    var len = arr.length - 1;
    if (len >= 0) {
        for (var i = 0;i < len; i++) {
            if (arr[i] !== arr[i+1]) {
                out.push (arr[i]);
            }
        }
        out.push (arr[len]);
    }
    

    至于您的实际问题,由于我不太了解 JavaScript,因此我将其作为算法来回答,但在我看来,您只记得上次传输的号码,例如:

    # Set up output array.
    
    out = []
    
    # Set up flag indicating first entry, and value of last added entry.
    
    first = true
    last = 0
    
    for i = 0 to arr.length-1:
        # Totally ignore undefined entries (however you define that).
    
        if arr[i] is defined:
            if first:
                # For first defined entry in list, add and store it, flag non-first.
    
                out.push (arr[i])
                last = arr[i]
                first = false
            else:
                # Otherwise only store if different to last (and save as well).
    
                if arr[i] != last:
                    out.push (arr[i])
                    last = arr[i]
    

    【讨论】:

    • 我喜欢这个逻辑,首先标记比检查数组输出长度是否为 0 更好
    【解决方案3】:

    这是一个单行:

    uniquify( myArray.filter(function(x){return true}) )
    

    如果你还没有写uniquify(你写的删除重复的函数),你也可以使用这个两行代码:

    var newArray = [];
    myArray.forEach(function(x) {
        if (newArray.length==0 || newArray.slice(-1)[0]!==x)
            newArray.push(x)
    })
    

    阐述:

    var a=[];
    a[0]=1; a[1]=undefined; a[2]=undefined;
    a[10]=2; a[11]=2;
    

    根据 OP,即使 a.length==12,数组也有“五个元素”。即使 a[4]===undefined,它根据他的定义不是数组的元素,不应包含在内。

    a.filter(function(x){return true}) 会将上述数组转换为[1, undefined, undefined, 2, 2]


    编辑: 这最初是用.reduce() 而不是.forEach() 编写的,但.forEach() 版本不太可能在低效时引入垃圾收集器和按值传递问题javascript的实现。

    对于那些担心与已有 6 年历史的 MIE8 浏览器的兼容性的人,该浏览器不支持最后两个版本的 ECMAScript 标准(甚至不完全兼容之前的版本),您可以包含代码https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach 但是,如果有人担心浏览器兼容性,则应该通过像 GWT 这样的交叉编译器进行编程。如果你使用jQuery,你也可以只用几个额外的字符来重写上面的内容,比如$.forEach(array, ...)

    【讨论】:

    • 请注意,这需要支持Array.reduce 的现代浏览器。例如,这不适用于
    • 感谢您的关注。然而,距离 IE8 发布已经过去了五年多。它发布的操作系统多年来已被微软正式终止。即使在 Windows 7 上,根据computerworld.com/s/article/9215845/… 的说法,微软已经开始为那些碰巧仍在使用 IE8 的计算机提供 PUSHED 弹出式下载(那是一年前的事了)。自 2009 年以来,这一直在 ECMAScript 5 标准中。没有 Array.map()/.filter()/.forEach() 的编程是一种没有比较的痛苦,让人想起 C。
    • 我说的不是那些未定义的,我说的是这里不会提醒的未定义for(var i=0;i&lt;array.length;i++){if(i in array){alert(array[i]);}}
    • @ninjagecko 2009 并不是“五年前”,IE
    • (第一个非测试版)IE8 于 2009 年发布,截至 2011 年 12 月仍有 22% 的市场份额,但如果您乐于忽略五分之一的潜在用户,请继续.请注意,由于工作场所 IT 政策的限制,很多人无法使用 IE9(例如,在我目前的工作场所,我们仍在使用 XP 和 IE_7_)。
    【解决方案4】:

    大概是这样的:

    var out = [],
        prev;
    
    for(var i = 0; i < arr.length; i++) {
       if (!(i in arr))
          continue;
    
       if (arr[i] !== prev || out.length === 0) {
          out.push(arr[i]);
          prev = arr[i];
       }
    }
    

    out.length 检查是允许当prev 最初也以undefined 开始时,第一个定义的数组元素的值为undefined

    请注意,与您的原始算法不同,如果 arr 为空,则不会将未定义的值推送到您的 out 数组中。

    或者,如果您有足够新的浏览器,您可以使用Array.forEach() method,它仅对已分配值的数组元素进行迭代。

    【讨论】:

    • 完美。我只需将等号符号更改为arr[i] !== prevout.length == 0。 (我认为这就是你的意思)
    • 谢谢。是的,我应该说arr[i] !== prev - 很好 - 我已经更新了我的答案以反映这一点。但我的意思是out.length === 0(数组长度总是数字)。
    • "数组长度永远是数字",那么为什么===?
    • 为什么不===?我使用== 只是为了能够比较(可能)不同类型的操作数,这些操作数可能被强制转换为相同的类型和值。
    • 我只使用===!== 时我认为强制可能会产生意想不到的东西,如果我确切地知道我在处理什么,并且==!= 永远不会让我遇到问题,我会使用它们并节省 1 个字符
    【解决方案5】:

    一种明确的方法是打包数组(删除undefined)值并使用您现有的算法来处理重复项..

    function pack(_array){
        var temp = [],
            undefined;
        for (i=0, len = _array.length; i< len; i++){
            if (_array[i] !== undefined){
                temp.push(_array[i]);
            }   
        }
        return temp;
    }
    

    【讨论】:

    • “打包”的想法也是我的第一个冲动,确保 undefined 确实是未定义的,但请注意,您的实现不符合 OP 区分数组元素的要求已分配 未定义(将被保留)和从未分配过值的索引(将被跳过)。
    • @nnnnnn,嗯.. 有效点,虽然我不确定这是否确实是 OP 所关心的.. 我把它理解为只是一个解释,值真的是未定义的.. 不是他想要一个对他们的不同处理..
    【解决方案6】:

    我想这就是你想要的。这是一个非常简单的算法。

    var out = [], previous;
    for(var i = 0; i < arr.length; i++) {
      var current = arr[i];
      if(!(i in arr)) continue;
      if(current !== previous) out.push(current);
      previous = arr[i];
    }
    

    这将在O(N) 时间运行。

    【讨论】:

    • 这不符合 OP 的要求,即区分已分配 value 未定义(将保留)的数组元素和从未有过赋值。
    • @nnnnnn 我不确定我是否理解,我问他想要什么行为,他只是说即使中间有未定义,也要删除欺骗。他不希望删除重复值之间分配给undefined 的值的数组的重复值吗?
    • 考虑:var arr=[]; arr[5]=1; arr[9]=undefined; arr[11]=undefined; arr[13]=3 - 在该代码之后 arr.length 是 14,但索引位置 0-4、6-8、10 和 12 从未被分配过值,它是那些 OP想跳过。索引 9 和 11 已明确分配 undefined,不应跳过。 OP 在帖子中途的“问题”标题下提到了这一点,但没有很好地解释它。然后是为了澄清的评论实际上使它不太清楚(所以也许我误解了)。
    • @PeterOlson 我的意思是未定义的不包含undefined 值。换句话说,它们不会出现在这里for(i=0;i&lt;array.length;i++){if(i in array){alert(array[i]);}}
    • 是的,这就是我要找的。很抱歉,我不太清楚的说明导致您在“nnnnnn”之后回答。我对这里发生的一切负全部责任。
    【解决方案7】:

    一个很简单的函数,输入数组必须排序:

    function removeDupes(arr) {
      var i = arr.length - 1;
      var o;
      var undefined = void 0;
    
      while (i > 0) {
        o = arr[i];
    
        // Remove elided or missing members, but not those with a 
        // value of undefined 
        if (o == arr[--i] || !(i in arr)) {
          arr.splice(i, 1);
        }
      }
      return arr;
    }
    

    它可能更简洁,但可能会变得模糊。顺便说一句,输入数组已被修改,因此它不需要返回任何内容,但如果返回可能会更方便。

    这是一个前向循环版本:

    function removeDupes2(arr) {
      var noDupes = [],
          o;
    
      for (var i=0, j=0, iLen=arr.length; i<iLen; i++) {
        o = arr[i];
        if (o != noDupes[j] && i in arr) {
           noDupes.push(o);
           j = noDupes.length - 1;
        }
      }
      return noDupes;
    }
    

    PS

    应该可以在任何支持 javascript 的浏览器上运行,无需任何额外的库或补丁。

    【讨论】:

    • 它会删除包含undefined 值的项目和假的undefined 值。 (我只想删除假的)
    • 非常简单的编辑来改变它(完成),虽然这是一个奇怪的要求
    【解决方案8】:

    此解决方案会就地删除重复元素。不推荐用于函数式编程

    const arr =[0,0,1,1,2,2,2,3,4,5,5,6,7,7,8,9,9,9];
    
    const removeDuplicates = (nums) => {
      nums.forEach((element, idx) => {
        nums.splice(idx, nums.lastIndexOf(element) - idx)
      })
    }
    
    removeDuplicates(arr)
    
    console.log(arr);

    【讨论】:

      【解决方案9】:
      //sort the array
      B.sort(function(a,b){ return a  - b});
      //removing duplicate characters
          for(var i=0;i < B.length; i ++){
              if(B[i]==B[i + 1])
                  B.splice(i,1)
          }
      

      如果下一个索引中的元素与当前位置相同,则删除该元素 当前位置

      splice(targetPosition,noOfElementsToBeRemoved)
      

      【讨论】:

        【解决方案10】:

        我相信你想要达到的目标不太可能,但我可能是错的。

        这就像经典的 CS 问题之一,比如村里的理发师只给不刮胡子的人刮胡子。 如果将数组的索引项的值设置为undefined,则它并不是真正的undefined。 不是这样吗?未初始化的值只能是undefined

        您应该检查的是值是null 还是undefined。如果null 或重复跳过该值,否则保留它。

        如果您试图跳过 null 值和重复项,那么下面的函数就可以解决问题。

        function  removeDuplicateAndNull(array){
        
            if(array.length==0)
                return [];
        
            var processed = [], previous=array[0];
            processed.push(array[0]);
        
            for(var i = 1; i < array.length; i++) {
        
                var value = array[i];
        
                if( typeof value !== 'undefined' && value ==null) 
                    continue;
        
                if(value !== previous || typeof value === 'undefined')
                    processed.push(value);
        
                previous = array[i];
            }
            return processed;
        }
        

        测试用例:

        1. array=[,5,5,6,null,7,7] output =[ ,5,6,7]

        2. array=[ 5,5,,6,null,,7,7] output=[5,,6,,7]

        3. array=[7,7,,] output=[7,]

        但即使有这个功能,也有一个警告。如果您检查第三个测试,则输出为 [7,] 而不是 [7,,] ! 如果检查输入和输出数组的长度,array.length =3 和 output.length=2。 需要注意的不是函数,而是 JavaScript 本身。

        【讨论】:

        • 接受的 ans 有效,它过滤未定义但尊重手动设置的未定义。将他的代码与 -> var arr=[];arr[3]=1;arr[5]=undefined;arr[6]=undefined;arr[8]=true;arr[10]=true; 一起使用,输出应为 1,,true
        【解决方案11】:

        这段代码是用 javascript 编写的。它非常简单。

        代码:

        function remove_duplicates(arr) {
                newArr = [];
                if (arr.length - 1 >= 0) {
                    for (i = 0; i < arr.length - 1; i++) {
                        // if current element is not equal to next
                        // element then store that current element
                        if (arr[i] !== arr[i + 1]) {
                            newArr.push(arr[i]);
                        }
                    }
                    newArr.push(arr[arr.length - 1]);
                }
                return newArr
            }
            arr=[0,1,1,2,2,3,4,5,5,6,7,7,8,9,9,9];
            console.log(remove_duplicates(arr));
        

        【讨论】:

          【解决方案12】:

          这是一个简单的 JavaScript 解决方案,不使用任何额外的空间。

          function removeDuplicates(A) {
             let i = 0;
             let j = i + 1;
             while (i < A.length && j < A.length) {
                if (A[i] === A[j]) {
                   A.splice(i, 1);
                   j=i+1;
                 } else {
                   i++;
                   j++;
                  }
               }
              return A;
             }
          console.log('result', removeDuplicates([0,1,1,2,2,2,2,3,4,5,6,6,7]))
          

          【讨论】:

            【解决方案13】:

            你可以试试简单的方法

            function hello(a: [], b: []) {
                 return [...a, ...b];
            }
            let arr = removeDuplicates(hello([1, 3, 7], [1, 5, 10]));
            arr = removeDuplicates(arr);
            function removeDuplicates(array) {
              return array.filter((a, b) => array.indexOf(a) === b);
            }
            let mainarr = arr.sort((a, b) => parseInt(a) - parseInt(b));
            console.log(mainarr); //1,3,5,7,10
            

            一个班轮代码

            [1,3,7,1,5,10].filter((a, b) => [1,3,7,1,5,10].indexOf(a) === b).sort((a, b) => parseInt(a) - parseInt(b))
            

            【讨论】:

              【解决方案14】:

              这是从排序数组中删除重复项的简单解决方案。

              时间复杂度 O(n)

              function removeDuplicate(arr) {
                      let i=0;
                      let newArr= [];
                      while(i < arr.length) {
                          if(arr[i] < arr[i+1]) {
                              newArr.push(arr[i])
                          } else if (i === (arr.length-1)) {
                              newArr.push(arr[i])
                          }
                          i++;
                      }
                      return newArr;
                  }
                  var arr = [1,2,3,4,4,5,5,5,6,7,7]
                  console.log(removeDuplicate(arr))

              【讨论】:

                【解决方案15】:

                假设您有一个排序数组,并且您不能使用其他数组来查找和删除重复项:

                在 Python 中

                def findDup(arr, index=1, _index=0):
                
                    if index >= len(arr):
                        return
                
                    if arr[index] != arr[_index]:
                
                        findDup(arr, index+1, _index+1)
                
                    if arr[index] == arr[_index]:
                        arr = deletedup(arr, index)
                        findDup(arr, index, _index) #Has to remain same here, because length has changed now
                
                
                
                def deletedup(arr, del_index):
                    del arr[del_index]
                    return arr
                
                arr = [1, 2, 3, 4, 4, 4, 5, 6, 7, 7, 7, 7, 7]
                
                findDup(arr)
                print arr
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2016-10-01
                  • 1970-01-01
                  • 2016-01-24
                  • 2021-11-12
                  • 2021-01-27
                  • 2014-10-15
                  • 1970-01-01
                  • 2022-01-03
                  相关资源
                  最近更新 更多