删除已排序数组上的重复项

时间:2012-02-20 02:14:35

标签: javascript arrays duplicates duplicate-removal sorted

万一你错过了,问题是删除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或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]);

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

14 个答案:

答案 0 :(得分:4)

使用.filter()的现代单缸纸

arr.filter((e, i, a) => 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]);

我个人不建议使用像这里其他答案中那样复杂的解决方案。

答案 1 :(得分:2)

这是一个单行:

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

答案 2 :(得分: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]

答案 3 :(得分:2)

也许是这样的:

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最初也以undefined开头时,prev检查是允许第一个定义的数组元素的值为undefined

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

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

答案 4 :(得分:1)

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

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)时间内运行。

答案 5 :(得分:1)

一种明确的方法是打包数组(删除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;
}

答案 6 :(得分:1)

一个非常简单的函数,必须对输入数组进行排序:

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的浏览器,无需任何其他库或补丁。

答案 7 :(得分:0)

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

这就像那些经典的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,]

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

答案 8 :(得分:0)

好的,我希望这不是重复但是假设您有一个已排序的数组,并且您不能使用其他数组来查找和删除重复项:

在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

答案 9 :(得分:0)

//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 :(得分:0)

此代码是用 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));

答案 11 :(得分:0)

这是不使用任何多余空间的简单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]))

答案 12 :(得分:0)

您可以尝试简单的方法

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

答案 13 :(得分:0)

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

时间复杂度 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))