【问题标题】:Evaluating Javascript Arrays评估 Javascript 数组
【发布时间】:2010-04-07 12:18:07
【问题描述】:

如果有意义的话,我有一个包含数组数组的数组。比如:

[[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]

我想看看数组中是否存在数组,所以如果 [1, 2, 3] 完全重复。我曾尝试使用 .indexOf 方法,但它确实找到了重复项。我还尝试过 Extjs 手动循环遍历数组并评估每个内部数组,我就是这样做的:

var arrayToSearch = [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]];        
var newArray = [1, 2, 3];
Ext.each(arrayToSearch, function(entry, index){
                    console.log(newArray, entry);
                    if(newArray == entry){
                        console.log(index);
                    };
                });

这也不会检测到重复项。 console.log 将输出 [1, 2, 3] 和 [1, 2, 3] 但不会将它们识别为相等。我也尝试过 === 评估器,但显然因为 == 不起作用 === 不起作用。我无能为力,任何建议。

【问题讨论】:

  • 您实际上只有一个数组数组。包含数组数组的数组将需要一组额外的方括号。

标签: javascript arrays extjs


【解决方案1】:

使用===== 比较两个数组将不起作用,因为它们不是同一个对象。如果要确定两个数组的元素相等性,则需要逐元素比较数组。

我怀疑你会从使用join(',') 之类的技巧然后使用字符串操作中获得什么。以下应该可以工作:

function arraysAreEqual (a, b) {
  if (a.length != b.length) {
    return false;
  }

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

  return true;
}

function containsArray (arrays, target) {
  for (var i=0; i<arrays.length; i++) {
    if (arraysAreEqual(arrays[i], target)) {
      return true;
    }
  }

  return false;
}

var arraysToSearch = [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]];
var newArray = [1, 2, 3];
containsArray(arraysToSearch, newArray);

【讨论】:

  • +1 用于提供代码。当然,这假设数组不包含无法通过== 比较的任何内容(例如其他数组)。但是 OP 的样本数据没有这些,所以...
【解决方案2】:

我经常发现比较两个数组的最佳方法是比较它们的连接值。

if(newArray.join('/') == entry.join('/')) ...

此外,您可能还想再投一张支票:

if(newArray.length == entry.length && newArray.join('/') == entry.join('/'))

如果长度检查无效,这是使比较无效的一种非常快速的方法,并且不需要进行连接,但检查也提高了比较的可靠性。例如,如果没有长度检查,以下数组在连接时会产生相同的结果:

var a = [1, '2/3'];
var b = [1, 2, 3];

通过长度检查,您确定不会发生这样的事情,并且不必担心转义分隔符或其他任何事情......

【讨论】:

  • 这不仅隐藏了您的意图,而且在内存和 CPU 使用方面也效率低下(在一般情况下)。如果您可以在几分钟内写出正确的比较,为什么还要这样做?
  • @z5h:您是否真的尝试过这两种方法并比较结果的性能? Array#join 和字符串比较可以发生在解释器的内部,而不是在解释的 JavaScript 代码中(在几乎所有主要浏览器上解释,Chrome 是反例——它可以编译!)。你可能会感到惊讶。在基于浏览器的 JavaScript 中,有一些表面上违反直觉的东西。
  • @z5h:我不同意这完全掩盖了程序员的意图。我认为这是一种非常直接的方法——左手和右手语句之间的简单比较在可读性方面几乎无法超越。当然代码应该优化为只加入newArray一次;我不知道 js 是否在本机上进行了优化……cpu 周期是否是优先事项,我将留给 OP 来决定。
  • 不,但我也很怀疑。这就是我写一般情况的原因。您还为需要进行垃圾收集的每个条目创建了一个新字符串。
  • @David:你有 13.4k 的声誉,而提出这个问题的人在一些相当简单的事情上遇到了麻烦。我只是认为 .join 解决方案不适合提出问题的人。此外,此人可能不明白,与 ['/','//'] 相比,['//','/'] 会失败。我没有对你投反对票,因为我认为你的回复中仍有很好的信息。
【解决方案3】:

不幸的是,在一般情况下,判断数组在这个意义上是否相等的唯一方法是比较它们的元素。没有捷径或内置方法可以做到这一点。

在某些特殊情况下,您可以使用Array#join 并比较结果字符串,例如:

var a = [1, 2, 3];
var b = [1, 2, 3];
alert(a.join(",") == b.join(",")); // Alerts "true"

...因为a.join(",") 产生字符串“1,2,3”,b.join(",") 也是如此。但显然,只有当您知道可以像这样有意义地连接和比较这些值时,您才能这样做。这样做可能(可能)更快,因为您可以利用 JavaScript 解释器的内部 join 和字符串比较方法,但同样,您不能在一般情况下这样做,只有当您知道数组中的数据可以被转换成字符串并像这样连接起来。

【讨论】:

    【解决方案4】:

    您需要编写一个辅助方法,逐个元素地比较 2 个数组并使用它来代替 ===。

    【讨论】:

      【解决方案5】:

      this answer 中的代码无法区分以下示例:

      javascript:
      function sameRAs(newArray,entry){
           return newArray.length == entry.length &&
                                        newArray.join('/') == entry.join('/')};
           alert( sameRAs(  [1,'2/3',4],  [1,2,'3/4']  )  ?  'same' : 'different' );
           alert( sameRAs(    [null],         [,]      )  ?  'same' : 'different' );
      

      要看到[null][,] 确实不同,请考虑:

       javascript:  alert( [null][0] );  alert( [,][0] );
      

      分别显示nullundefined


      复合数组可以检查数组的身份! == 用于相同的数组!

       javascript:
            ra=[1,2,3]; ar=[4]; r=[]; composite=[ar,r,ra,ar,ra];
            for(i in composite)
               if(composite[i]==ra)
                  alert( JSON.stringify(composite) +' at ['+ i +']'+' == ['+ ra +']')
      

      显示:

      [[4],[],[1,2,3],[4],[1,2,3]] at [2] == [1,2,3]
      

      [[4],[],[1,2,3],[4],[1,2,3]] at [4] == [1,2,3]
      

      虽然我投票支持 .toSource() (& Mozilla),但可以通过 JSON 比较简单的值数组。

       javascript:
            ra=[1,2,3]; ar=[1,2,3];
            alert([  ra==ar,   JSON.stringify(ra)==JSON.stringify(ar)  ]);
      

      显示false,true


      另一个问题:圆形数组。比较这些是困难的,这就是 .toSource() 的亮点。

      javascript:
         ra = [0,1,2];   ra[3] = ra;      r2d2 = #2= [0,1,2,#2#];
         alert([ ra==r2d2,  ra.toSource() == r2d2.toSource() ])
      

      显示 false,true(在 FireFox 中)。


      关于机器效率:与投入人力时间的成本相比,计算费用是微不足道的。计算机的存在是为了减少人力,而不是相反。真正计算成本高且部署广泛的计算可能需要对人力进行大量投资以实现效率。这不是那些时代之一。

      .toSource() 的简单性可能会通过安装 FF 作为解决此类问题的实用方法来获得回报。问题的规模通常意味着强迫环境和机器寻求解决方案,而不是使用人力。

      【讨论】:

        【解决方案6】:

        探索的一种可能替代方法是使用 Array.toSource():

        >>> [3, 2, 1].toSource() == [3, 2, 1].toSource()
        true
        

        【讨论】:

        • 嗯,似乎可以工作...(但并非在所有浏览器中...IE6、IE7、IE8、Chrome、Safari 和 Opera 失败)
        • 啊,我知道我没有使用它是有原因的 :)
        【解决方案7】:

        本着有趣的挑战精神,我编写了以下函数。它可以工作并处理(数组、对象、数字、日期、函数和字符串)的简单情况

        注意:如果您传递 {document} 之类的内容,您将进入一个痛苦的世界,但简单的东西有效。

        function compare(a,b){
          if(a instanceof Array && b instanceof Array){
            if(a.length != b.length){
              return false;
            }
            for(var i=0,l=a.length;i<l;i++){
              if(!compare(a[i], b[i])){
              return false;
              }
            }
            return true;
          } else if(typeof(a) == 'object' && typeof(b) == 'object'){
            var keys = {};
            for(var i in a){
              keys[i] = true;
              if(!compare(a[i], b[i])){
              return false;
              }
            }
            //what if b contains a key not in a?
            for(var i in b){
              if(!keys[i]){
              return false;
              }
            }
            return true;
          } else {
            return (a == b);
          }
        }
        
        var someDate = new Date();
        var someFunc = function(){alert('cheese');};
        
        var foo = {};
        foo['a'] = 'asdf';
        foo['b'] = 'qwer';
        foo['c'] = 'zxcv';
        foo['d'] = ['a','b','c','d','e'];
        foo['e'] = someDate;
        foo['f'] = 34;
        foo['g'] = someFunc
        
        var bar = {};
        bar['a'] = 'asdf';
        bar['b'] = 'qwer';
        bar['c'] = 'zx' + 'cv';
        bar['d'] = ['a','b','c','d','e'];
        bar['e'] = someDate;
        bar['f'] = 34;
        bar['g'] = someFunc
        
        if(compare(foo, bar)){
          alert('same!');
        } else {
          alert('diff!');
        }
        

        【讨论】:

        • typeof 何时何地返回“数组”?这是 JavaScript 最著名的“坏部分”之一......
        • 您可能希望在您的for ... in 循环中进行hasOwnProperty 检查,这样您就不会遍历原型链中的所有属性。
        猜你喜欢
        • 2018-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-28
        相关资源
        最近更新 更多