2010-04-07 8 views
3

J'ai un tableau qui contient un tableau de tableaux si cela a du sens. Ainsi, par exemple:Évaluation des tableaux Javascript

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

Je veux voir si un tableau existe withing le tableau, donc si [1, 2, 3] est reproduite à tous. J'ai essayé d'utiliser la méthode .indexOf mais elle trouve le doublon. J'ai aussi essayé Extjs en boucle à travers le réseau manuellement et d'évaluer chaque tableau intérieur, voici comment je l'ai fait:

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

Cela aussi ne détecte pas le double. Le fichier console.log affichera [1, 2, 3] et [1, 2, 3] mais ne les reconnaîtra pas comme égaux. J'ai aussi essayé l'évaluateur === mais évidemment puisque == ne fonctionne pas, le === ne fonctionnera pas. Je suis à la fin de l'esprit, des suggestions.

+1

Vous avez juste un tableau de tableaux.Un tableau qui contient un tableau de tableaux nécessiterait un ensemble supplémentaire de crochets. – tloflin

Répondre

10

La comparaison des deux tableaux en utilisant == ou === ne fonctionnera pas car ils ne sont pas le même objet. Si vous souhaitez déterminer l'égalité élément par élément de deux tableaux, vous devez comparer les tableaux par élément.

Je doute que vous obtiendrez quelque chose en utilisant des astuces comme join(','), puis en utilisant des opérations de chaîne.Ce qui suit devrait fonctionner cependant:

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

+1 pour fournir le code. Bien sûr, cela suppose que les tableaux ne contiennent rien qui ne puisse être comparé via '==' (comme les autres tableaux). Mais les exemples de données de l'OP n'en ont pas, alors ... –

1

Vous devez écrire une méthode d'assistance qui compare 2 tableaux par élément et l'utiliser au lieu de ===.

2

Malheureusement, dans le cas général, la seule façon de savoir si les tableaux sont égaux dans ce sens est de comparer leurs éléments. Il n'y a pas de raccourci ou de façon intégrée de le faire.

Dans certains cas particuliers, vous pouvez vous rendre la vie un peu plus facile en utilisant Array#join et en comparant les chaînes résultantes, par exemple:

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

... parce que a.join(",") résultats dans la chaîne « 1,2,3 » , tout comme b.join(","). Mais évidemment, vous ne pouvez le faire que lorsque vous savez que vous pouvez concaténer et comparer les valeurs de manière significative. Cela peut (peut) être plus rapide parce que vous pouvez tirer parti des méthodes de comparaison interne join et chaîne de l'interpréteur JavaScript, mais encore une fois, vous ne pouvez pas le faire dans le cas général, seulement quand vous savez que les données du tableau vont être d'accord avec être transformé en une chaîne et concaténés comme ça.

3

J'ai souvent trouvé que la meilleure façon de comparer deux tableaux est de comparer leurs valeurs de jointure.

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

De plus, vous voudrez peut-être jeter un plus vérifier:

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

Si le contrôle de longueur est invalidée, c'est un moyen très rapide de vicier la comparaison et pas pris la peine de faire les jointures, mais le contrôle améliore également la fiabilité de la comparaison. Par exemple, sans le contrôle de la longueur, les tableaux suivants produiraient le même résultat lorsqu'ils sont joints:

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

Avec le contrôle de longueur, vous êtes sûr que quelque chose comme cela ne peut se produire, et ne pas avoir à se soucier à propos de l'échappement des délimiteurs ou quoi que ce soit ...

+1

Non seulement cela cache votre intention, mais il est également inefficace en termes de mémoire et d'utilisation du processeur (dans le cas général). Pourquoi faire cela quand vous pourriez écrire une comparaison correcte dans quelques minutes? – z5h

+0

@ z5h: Avez-vous * essayé * les deux méthodes et comparé les performances des résultats? 'Array # join' et la comparaison de chaînes peut se produire dans les tripes de l'interpréteur, plutôt que d'être dans du code JavaScript interprété (interprété sur presque tous les principaux navigateurs, Chrome étant le contre-exemple - il compile!). Vous pourriez bien être surpris. Il y a plusieurs de ces choses contre-intuitives sur le visage dans le JavaScript basé sur le navigateur. –

+0

@ z5h: je ne suis pas d'accord que cela obscurcit l'intention du programmeur. Je pense que c'est une approche très simple - une simple comparaison entre une déclaration de gauche et une affirmation de droite ne pourrait guère être dépassée en termes de lisibilité. bien sûr, le code devrait être optimisé pour ne joindre qu'une seule fois 'newArray'; Je ne sais pas si js optimise cela nativement ... si les cycles de cpu sont une priorité je pars pour OP de décider. –

0

Dans l'esprit d'un défi intéressant, j'ai écrit la fonction suivante. Il fonctionne, et gère des cas simples de (tableaux, objets, nombres, dates, fonctions, & chaînes)

Note: Si vous passez des choses comme {document} vous êtes dans un monde de mal, mais les choses simples travaux.

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

Quand et où typeof retourne-t-il "array"? C'est l'une des "mauvaises" parties les plus connues de JavaScript ... – ken

+0

Ah, merci @ken, j'ai copié le mauvais code de ma page de test. – scunliffe

+1

Vous pouvez faire des vérifications 'hasOwnProperty' dans vos boucles' for ... in' afin de ne pas passer en revue toutes les propriétés de la chaîne prototype. – ntownsend

0

Une alternative possible à explorer serait d'utiliser Array.toSource():

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

Hmm, semble fonctionner ... (mais pas dans tous les navigateurs ... IE6, IE7, IE8, Chrome, Safari et Opera échoue) – scunliffe

+1

Ah, je savais qu'il y avait une raison pour laquelle je ne l'ai jamais utilisé :) – ken

1

Le code this answer ne parvient pas à différencier les exemples:

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

Pour voir que [null] et [,] sont en effet différents, considèrent:

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

qui affichent null et undefined respectivement. Un tableau composé peut vérifier l'identité d'un tableau!


avec == pour des tableaux identiques!

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

affiche:

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

et

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

Alors que mon vote est avec .toSource() (& Mozilla), simples tableaux de valeur peuvent être comparés via JSON.

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

affiche false,true.


Une autre ride: les réseaux circulaires. Il est difficile de les comparer, c'est là que brille .toSource().

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

affiche false,true (dans FireFox). En ce qui concerne l'efficacité de la machine: la dépense de calcul est marginale par rapport au coût investi dans le temps humain. Les ordinateurs sont là pour réduire le travail humain, et non l'inverse. Des calculs vraiment coûteux et largement déployés peuvent justifier un investissement important dans le travail humain pour réaliser des gains d'efficacité. Ce n'est pas un de ces temps.

La simplicité de .toSource() peut être payante en installant FF comme une approche pragmatique pour résoudre des problèmes tels que celui-ci. L'ampleur d'un problème signifie souvent contraindre l'environnement et la machinerie à trouver une solution plutôt que d'utiliser le travail humain.