1

原始主题,我知道,但是任何人都可以评论以下用于比较两个 ES5 数组的算法:

function equal_arrays(a, b) {
    "use strict";

    var c = 0;

    return a.every(function (e) {
        return e === b[c++];
    });
}

我认为这是非常干净和明显的使用 [].every() 来快速比较两个数组?我有那种唠叨“肯定不会那么简单吧?” 感觉如何?

注意:当两个数组在同一位置包含严格相等的所有元素时,它们是相等的。所以元素索引和元素值都必须完全相等。不同类型的值被认为是不相等的。还比较了稀疏数组。

测试用例:

      equal_arrays([],[]) ; // => true
      equal_arrays([1,2],[1,2]) ; // => true
      equal_arrays([1,,2],[1,,2]) ; // => true
      equal_arrays([,],[,]); // => true
      equal_arrays([1,,3,,,],[1,,3,,,]); // => true

使用案例产生 => false,可以想象自己。比较非数组是语法错误。

非常感谢善意和乐于助人的贡献者。似乎“最好的”(从来没有这样的事情)实现是这样的:

function has(element, index)
{
    return this[index] === element;
}

function equal_arrays(a, b)
{
    return (a.length === b.length) && a.every(has, b) && b.every(has, a);
}

@tom 的双向 every() 实现是必要的,这样的测试用例可以工作:

equal_arrays([1,,3],[1,2,3]); //=> false 

再次感谢...

4

4 回答 4

4

不,它无效。来自MDN 文档

callback仅对具有赋值的数组索引调用;对于已被删除或从未被赋值的索引,它不会被调用。

因此,如果第一个数组有“间隙”,它们将被跳过。

equal_arrays([1, 2, , 4], [1, 2, 4]); // true
equal_arrays([1, 2, 4], [1, 2, , 4]); // false

这是一个更好的实现:

function equal_arrays(a, b) {
    if (a.length != b.length) return false;
    var i;
    for (i = 0; i < a.length; i++) {
        if (a[i] !== b[i]) return false;
    }
    return true;
}

这是@RobG 的双向every()想法的优雅实现:

function has(element, index)
{
    return this[index] === element;
}

function equal_arrays(a, b)
{
    return (a.length === b.length) && a.every(has, b) && b.every(has, a);
}
于 2013-07-11T23:09:16.867 回答
3

我有那种唠叨“肯定不会那么简单吧?” 感觉如何?

不,不是。使用each on one 数组将针对数组的每个成员而不是另一个成员进行测试。你必须测试两种方式。

此外,这取决于您对“平等”的标准。您可能希望同一索引的每个成员都具有相同的值,但您可能不关心顺序,所以[1,2]等于[2,1]? [,,,2]等于[2]? _

此外,应该[1,,2]equal [1,undefined,2],即不存在的成员是否应该与存在但具有 value 的成员“相等” undefined

数组比较函数

以下可能会完成这项工作。它比较两种方式,检查自己的属性和值。我认为它涵盖了所有情况,但我愿意相信其他情况。作为一个单独的函数可能会更好,但添加到 Array.prototype 很方便。

// Test that own properties of two arrays have the same values
Array.prototype.isEqualTo = function(a) {
  var visited = {};
  if (this.length != a.length) return false;

  // Test every own property of this, remember tested properties
  for (var p in this) {

    if (this.hasOwnProperty(p)) {
      visited[p] = p;

      if (!(a.hasOwnProperty(p)) || this[p] !== a[p]) {
        return false; 
      }
    }
  }

  // Reverse test that comparison array only has tested properties
  for (var q in a) {
    if (a.hasOwnProperty(q) && !(q in this)) {
      return false;
    }
  }
  return true;
}

console.log([1,,2].isEqualTo([1,undefined,2])); // false, not defined != undefined
console.log([1,,2].isEqualTo([1,2]));           // false, different length
console.log([1,2].isEqualTo([1,2]));            // true

请注意,应该忽略继承的属性,就像比较来自不同窗口的数组(例如,一个来自框架)然后继承的属性将不相等。

于 2013-07-11T23:10:00.870 回答
2

作为替代方案,如果您只想检查两个数组是否完全相同,您可以这样做:

var a = [1,2,3,4];
var b = [1,2,3,4];

JSON.stringify(a) == JSON.stringify(b); //= true

这应该适用于数字和字符串数组。

于 2013-07-11T23:03:56.630 回答
2

正如 CrazyTrain 所说,增量值没用,您需要先检查长度:

function equalArrays( a, b ) {
  "use strict";
  if (a.length !== b.length) return false;
  return a.filter(function(el){ return el;}).every(function(e, i) {
    return e === b[i];
  });
}

是按值比较数组的有效算法。

于 2013-07-11T23:07:36.973 回答