【问题标题】:Comparing arrays in javascript where order doesn't matter比较顺序无关紧要的javascript中的数组
【发布时间】:2018-05-19 21:00:34
【问题描述】:

我正在学习 Javascript,我在 SO 上看到了一个函数,用于比较数组以检查它们是否相同。但是,如果两个数组是 [string1,string2] 和 [string2,string1],我当前的函数会返回 false。基本上,这两个位置是互换的。代码如下:

function _compareArrays(arr1,arr2){
    var result = arr1 != null && arr2 != null && arr1.length == arr2.length && arr1.every(function(element) {
            return arr2.indexOf(element);
        });
    return result ;
}

但是,我希望这两个数组返回相同。所以,我将.every 更改为.indexOf(),它似乎有效。但是,我有一个疑问,计数器究竟是如何在这里递增以确保对每个元素都进行比较的? 我的意思是,就像在 C++ 中,我们这样做,

for (int i = 0; i < 10; i++)
    if (arr1[i] == arr2[i]
      cout<<"Elements are same\n";

在这里,我有一个明确的i++,它增加了计数器。在上述函数中它是如何发生的?

谢谢!

【问题讨论】:

  • 你的第一个代码块完全是垃圾。 indexOf 在我读过的任何文档中都没有将函数作为参数 - So, I changed .every to .indexOf() 当你的轮胎漏气时,你会用香蕉代替车轮吗?
  • 我只是 create shallow copies 的数组,对它们进行排序,然后使用您提到的比较机制
  • 您定义的_compareArrays 方法总是返回-1。至于every 方法如何在不显式递增计数器的情况下进行迭代:它是 Array 原型上的一个函数,可以自动进行迭代。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 看看我编辑的函数,上面的函数会不会也不起作用?
  • @sarah 再次查看我的答案。

标签: javascript arrays


【解决方案1】:

你的当前有这些问题:

  1. 它将为这 2 个数组返回 true(我希望您理解这不是特定于这 2 个):[1, 2, 2][1,1,2]。这个问题就是为什么我在下面的解决方案中将索引设置为undefined

  2. indexOf 为它找不到的元素返回-1,任何数字&gt;= 0 如果它可以找到该元素,-1 是真实的,所以如果一个元素找不到,你的比较将返回true , 而0 是假的,所以如果一个元素位于第二个数组的第一个索引中,您的方法将返回false(这意味着整个事情将变为false,因为every... )。因此,您应该在indexOf 调用的结果之前添加~~arr2.indexOf(element)

    this MDN 页面上的 Bitwise Not 运算符 (~) 以及它如何解决 indexOf我提到的问题。

    我还建议您查看我的this 对真值/假值的回答以及它们如何与&amp;&amp;|| 交互。


所以试试这个(这主要是你的例子,除了没有使用 indexOf 并且我已经解决了问题 #2):

function _compareArrays(arr1,arr2){
  if(!(arr1 != null && arr2 != null && arr1.length == arr2.length)) {
    return false;
  }

  /* copy the arrays so that the original arrays are not affected when we set the indices to "undefined" */
  arr1 = [].concat(arr1);
  arr2 = [].concat(arr2);

  return arr1.every(function(element, index) {
    return arr2.some(function(e, i) {
      return e === element && (arr2[i] = undefined, true);
    });
  });
}
    
var x = ["str", "boo", "str"];
var y = ["boo", "str", "str"];
var z = ["abc", "def", "ghi"]    

console.log(_compareArrays(x, y));
console.log(_compareArrays(x, z));
console.log(_compareArrays(z, z));

如果数组有任何 undefined 元素,它将不起作用。

【讨论】:

  • 为什么要更改数组的值?我想保留这些值。
  • 您可以在函数开始时将所有未定义的值设置为 null。但这将是一个有点笨拙的解决方案。
  • @sarah 否则,[1, 2, 1] 将被标记为等于 [1, 2, 2]
  • @nipuna777 我相信这个问题有解决方案,也许我能找到,但我现在要去上学了。
  • @nipuna777,我尝试在比较之前对数组进行排序。但这也没有用。您认为为什么会发生这种情况?
【解决方案2】:

将数组转换为对象。将数组值转换为键,并将它们各自的计数作为它们的值。当您只对数组进行一次迭代时,这会更高效。

function compare(a, b) {
  if (a.length !== b.length) {
    return false;
  }
  let set = {};
  a.forEach((i) => {
    if (set[i] !== undefined) {
      set[i]++;
    } else {
      set[i] = 1;
    }
  });
  let difference = b.every((i) => {
    if (set[i] === undefined) {
      return false;
    } else {
      set[i]--;
      if (set[i] === 0) {
        delete set[i];
      }
      return true;
    }
  });
  return Object.keys(set) == 0 && difference;
}

第一个数组上的第一个循环初始化集合(对象),第二个数组上的第二个循环减去计数并在计数达到 0 时删除键。如果找不到键或集合不存在过程结束时为空,则数组不相似。

【讨论】:

    【解决方案3】:

    因此,最快的方法是对两个数组进行排序,然后逐个元素进行比较。这需要 2n * log(n) + n 时间而不是 n2 时间。

    function compareArrays(arr1, arr2){
      if(arr1.length !== arr2.length) return false;
    
      // implement custom sort if necessary
      arr1.sort();
      arr2.sort();
    
      // use normal for loop so we can return immediately if not equal
      for(let i=0; i<arr1.length; i++){
        if(arr1[i] !== arr2[i]) return false;
      }
    
      return true;
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-09
      • 1970-01-01
      • 2014-03-21
      • 2017-05-03
      • 2020-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多