开发者

Evaluating Javascript Arrays

开发者 https://www.devze.com 2022-12-25 18:11 出处:网络
I have an array that contains an array of arrays if that makes any sense. so for example: [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]

I have an array that contains an array of arrays if that makes any sense. so for example:

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

I want to see whether an array exists withing the array, so if [1, 2, 3] is duplicated at all. I have tried to use the .indexOf method but it does find the duplicate. I have also tried Extjs to loop through the array manually and to evaluate each inner array, this is how I did it:

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

This also does not detect the duplicate. the console.log will output [1, 2, 3] and [1, 2, 3] but will not recognize them as equal. I have also tried the === evaluator but obviously since == doesn't work the === wont work. I am at wits end, any suggestions.


Comparing the two arrays using == or === will not work because they are not the same object. If you want to determine the element-wise equality of two arrays you need to compare the arrays element-wise.

I doubt you'll gain anything from using tricks like join(',') and then using string operations. The following should work though:

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


I've often found that the best way to compare two arrays is to compare their join values.

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

Additionally, you may want to throw in one more check:

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

If the length check is invalidated, that's a really quick way of invalidating the comparison and not bother with doing the joins, but the check also improves the reliability of the comparison. For instance, without the length check, the following arrays would yield the same result when joined:

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

With the length check, you're sure something like this can't happen, and don't have to worry about escaping delimiters or anything...


Unfortunately, in the general case, the only way you can tell if arrays are equal in this sense is to compare their elements. There's no shortcut or built-in way of doing that.

In some special cases you can make your life a bit easier by using Array#join and comparing the resulting strings, e.g.:

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

...because a.join(",") results in the string "1,2,3", as does b.join(","). But obviously you can only do that when you know that you can concatenate and compare the values meaningfully like that. Doing this may (may) be faster because you can leverage the JavaScript interpreter's internal join and string comparison methods, but again, you can't do this in the general case, only when you know the data in the array is going to be okay with being turned into a string and concatenated like that.


You need to write a helper method that compares 2 arrays element by element and use that instead of ===.


The code in this answer fails to differentiate the examples in:

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

To see that [null] and [,] are indeed different, consider:

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

which display null and undefined respectively.


A composited array can check array identity! with == for identical arrays!

 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 +']')

displays:

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

and

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

While my vote is with .toSource() (& Mozilla), simple valued arrays can be compared via JSON.

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

displays false,true.


Another wrinkle: circular arrays. Comparing these is difficult, which is where .toSource() shines.

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

displays false,true (in FireFox).


Regarding machine efficiency: the computational expense is marginal compared to the cost invested in human time. Computers are here to reduce human labour, not the other way around. Truly computationally expensive and extensively deployed computations may warrant a large investment in human labour to realize efficiencies. This is not one of those times.

The simplicity of .toSource() might payoff by installing FF as a pragmatic approach to solving problems such as this. The scale of a problem often means coercing the environment and machinery to get a solution rather than using human labour.


One possible alternative to explore would be using Array.toSource():

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


In the spirit of an interesting challenge, I wrote the following function. It works, and handles simple cases of (arrays, objects, numbers, dates, functions, & strings)

Note: If you pass it things like {document} you are in for a world of hurt, but the simple stuff works.

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!');
}
0

精彩评论

暂无评论...
验证码 换一张
取 消