取两个数组的差异并制作一个新数组

时间:2015-06-02 01:52:06

标签: javascript

我需要这个函数来比较两个数组并返回一个新数组,该数组只包含两个数组都不常见的元素。我写了以下代码:

function diff(arr1, arr2) {

  var newArray = [];

  for (var i=0;i<arr1.length;i++){
    for (var j=0;j<arr2.length;j++){
      if (arr1[i]===arr2[j]){

        arr1.splice(i,1);
        arr2.splice(j,1);
      }
    }
  }
  newArray = arr1.concat(arr2);
  return newArray;
}

diff([1, 2, 3, 5], [1, 2, 3, 4, 5]);

但它返回[2,2,4]而不仅仅是[4]

另外,我尝试使用过滤方法编写它:

function diff(arr1, arr2) {

  var newArray = [];

  function compare(x){
    for (var i = 0;i<arr2.length;i++){
      return x != arr2[i];
    }
  }
  newArray = arr1.filter(compare);
  return newArray; 
}

diff([1, 2, 3, 5], [1, 2, 3, 4, 5]);

并且这对每个实例都不起作用。 我需要能够将数组与数字和字符串进行比较。 它必须是javascript,没有jquery。

7 个答案:

答案 0 :(得分:2)

你可以尝试:

function diff(arr1, arr2) {

    var tmp = [];
    var newArray = [];

    for (var i = 0; i < arr1.length; i++) {
        for (var j = 0; j < arr2.length; j++) {
            if (arr1[i] === arr2[j]) {
                arr1[i] = arr2[j] = null;
            }
        }
    }
    tmp = arr1.concat(arr2);
    for (var i = 0; i < tmp.length; i++) {
        if (tmp[i] !==null) {
            newArray.push(tmp[i]);
        }
    }
    return newArray;
}

console.log(diff([0,1,2], [1,2]));//output: [0]

答案 1 :(得分:1)

当你splice数组中所有元素向下移动时,这会让你的循环跳跃一步。例如,当它删除1位置中的0th时,2移动到新的0th部分,您已经检查过它会跳过下一个。解决这个问题的一个简单方法是,当你拼接确保你退步时,你可以减少ij

  if (arr1[i]===arr2[j]) {
    arr1.splice(i,1);
    arr2.splice(j,1);
    i--; 
    j--;  
  }

答案 2 :(得分:0)

.splice改变了数组,所以它与你的循环混乱。对代码的一个简单修复就是以相反的顺序迭代:

for (var i=arr1.length; i--;){
  for (var j=arr2.length; j--){

  }
}

然而,仍有问题是您经常拼接arr1arr1每次迭代只能拼接一次:

for (var i=arr1.length; i--;){
  var same = false;
  for (var j=arr2.length; j--;){
    if (arr1[i] === arr2[j]) {
      same = true;
      arr2.splice(j, 1);
      break;
    }
  }
  if (same) {
    arr1.splice(i, 1);
  }
}

function diff(arr1, arr2) {
  for (var i = arr1.length; i--;) {
    var same = false;
    for (var j = arr2.length; j--;) {
      if (arr1[i] === arr2[j]) {
        same = true;
        arr2.splice(j, 1);
        break;
      }
    }
    if (same) {
      arr1.splice(i, 1);
    }
  }
  return arr1.concat(arr2);
}

console.log(diff([1, 2, 3, 5], [1, 2, 3, 4, 5]));

答案 3 :(得分:0)

对两个数组进行排序,从中删除重复项,连接两个数组,对获取的数组进行排序,并从获取的数组中删除重复项。

function getArraysDifference(a1, a2) {

    sortAndRemoveDuplicates(a1);
    sortAndRemoveDuplicates(a2);
    var outputArray = a1.concat(a2)
    sortAndRemoveDuplicates(outputArray);
    return outputArray; 

}

function sortAndRemoveDuplicates(inputArray) {

    inputArray.sort();
    var lastValue = inputArray[0];
    var i = 0;
    var currentValue;

    for (i = 1; i < inputArray.length; i++) {

        currentValue = inputArray[i];

        if (currentValue === lastValue) {
            inputArray.splice(i, 1);
            i--;
        } else {
            lastValue = currentValue;
        }

    }

}

您的最坏情况时间复杂度为O((N + M)log(N + M))。您尝试的解决方案有效但时间复杂度为O(N * M)。

修改

事实证明,由于webkit(我没有在其他浏览器上调查)使用选择排序进行排序,因此该解决方案导致时间复杂度O(N M)。 在Java中,这种方法应该更快,因为引擎甚至可以达到O(N)来排序合理的短数组,否则会降低O(N log(N))复杂度以进行排序。

答案 4 :(得分:0)

设置临时对象。迭代两个数组。对于每个数组中的每个元素,如果该元素不是临时对象中的键,则将该对象中的键设置为等于该值为true的元素。如果已访问过某个元素,请将其删除。

最后,返回Object.keys(obj)以获取键的数组。

function differenceOfTwoArrays(arr1, arr2) {
  var obj = {};

  arr1.forEach(function(elem) {
    if (!obj[elem]) {
      obj[elem] = true;
    } else if (obj[elem]) {
      delete (obj[elem]);
    }
  });

  arr2.forEach(function(elem) {
    if(!obj[elem]) {
      obj[elem] = true;
    } else if (obj[elem]) {
      delete (obj[elem]);
    }
  });

  return Object.keys(obj);
}

答案 5 :(得分:0)

代码少于其他答案:

function diff(arr1, arr2) {
  var newArray = [];
  for (var i=0;i<arr1.length;i++) {
    if (arr2.indexOf(arr1[i]) == -1) newArray.push(arr1[i]);
  }
  for (var i=0;i<arr2.length;i++){
    if (arr1.indexOf(arr2[i]) == -1) newArray.push(arr2[i]);
  }
  return newArray;
}

修改: 比较一些答案: https://jsfiddle.net/c42wvvr5/2/

似乎这个答案在Chrome上是最快的,而且比在Firefox上的杨稍慢。

将数组值转换为对象键可以加快速度:

function diff_dms2(arr1, arr2) {
  var newArray = [];
  var ob1 = { };
  var ob2 = { };
  for (var i=0; i<arr1.length; i++) ob1[arr1[i]] = true;
  for (var i=0; i<arr2.length; i++) ob2[arr2[i]] = true;
  for (var i=0;i<arr1.length;i++) {
    if (!ob2[arr1[i]]) newArray.push(arr1[i]);
  }
  for (var i=0;i<arr2.length;i++){
    if (!ob1[arr2[i]]) newArray.push(arr2[i]);
  } 
  return newArray;
}

我会选择代码更简单的那个,除非你有非常庞大的数组。

答案 6 :(得分:0)

这是一个有趣的参考&#34;实现。它的目的不是特别快速或有效,而是要正确并从代码中阐明算法,这有助于确保正确性。你可以写得更好&#34;版本并将它们与正确性进行比较。 &#34;自动化测试是最佳测试。&#34; : - )

它完全按照问题中的说明进行:元素 - 不一定是整数 - 两个数组共有的数据都从两个数组中删除。这意味着一个阵列中的重复项目在另一个阵列中找不到,而另一个未触及。

&#13;
&#13;
function arrayDiff( array1, array2 ) {
    var r1 = array1.slice();
    var r2 = array2.slice();
    var r1Unique = []; // collector for known "unique" values
    while( !r1.every( function( r1Obj ) {
        var uniqueR1Obj = r2.every( function( r2Obj ) {
            if( r1Obj !== r2Obj ) {
                return true; // unique so far, keep processing
            }
            // collision: remove all references to this object in R2
            var newR2 = [];
            r2.forEach( function( oldR2Obj ) {
                if( oldR2Obj !== r2Obj ) {
                    newR2.push( oldR2Obj );
                }
            } );
            r2 = newR2; // start operating on the new smaller array
            return false; // uniqueness lost, bail
        } );
        if( uniqueR1Obj ) {
            r1Unique.push( r1Obj );
        }
        // remove all references to this object in R1
        var newR1 = [];
        r1.forEach( function( oldR1Obj ) {
            if( oldR1Obj !== r1Obj ) {
                newR1.push( oldR1Obj );
            }
        } );
        r1 = newR1; // start operating on the new smaller array
        return uniqueR1Obj; // keep processing if still unique, or bail
    } ) );
    return r1Unique.concat( r1.concat( r2 ) );
}

function addTestResults( r1, r2 ) {
    var s = 'arrayDiff( [ ' + r1 + ' ], [ ' + r2 + ' ] ) == [ ' + arrayDiff( r1, r2 ) + ' ]<br/>';
    el = document.getElementById( "output" );
    if( el !== null )
        el.innerHTML += s;
}

var testArray1 = [ 1, 2, 4, 8, 16, 32, 0 ];
var testArray2 = [ 1, 1, 3, 8, 15 ];
var testArray3 = [ 32, 3, 8, 0, 8, 8, 15 ];
            
addTestResults( testArray1, testArray2 );
addTestResults( testArray2, testArray3 );
addTestResults( testArray1, testArray3 );
&#13;
<pre id="output"></pre>
&#13;
&#13;
&#13;

这一点HTML只是作为一个&#34;输出设备&#34;。我不是代码片段的专家。

以下是另一种观看方式:http://jsfiddle.net/Lp1zveba/

附录:我还不能对其他答案发表评论,但我like the one来自rkho&#39;这是对它和我的提交的比较:http://jsfiddle.net/uuh7afLc/

它显示了一些差异,我将对这个问题进行不同的解释;我完全认为,如果一个元素在两个数组之间是通用的,那么它(及其所有类型)将不会出现在结果数组中。其他一些答案使用对于每个类似对象的替代解释,一个从每个源数组中移除,并且任一阵列中任何不匹配的剩余部分都会在到达结果数组的过程中存活。

鼓励Asker澄清规范。 : - )