Existe-t-il un moyen de renvoyer la différence entre deux tableaux en JavaScript?
Par exemple:
var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
// need ["c", "d"]
javascript
arrays
array-difference
John Adawan
la source
la source
O(a1.length x log(a2.length))
- cette performance est-elle possible en JavaScript?Réponses:
Je suppose que vous comparez un tableau normal. Sinon, vous devez remplacer la boucle for par une boucle for .. in .
Une meilleure solution, si vous ne vous souciez pas de la compatibilité descendante, utilise le filtre. Mais encore, cette solution fonctionne.
la source
var a1 = ['a', 'b'];
etvar a2 = ['a', 'b', 'c', 'd', 'b'];
, cela retournera une mauvaise réponse , c'est-à-dire['c', 'd', 'b']
au lieu de['c', 'd']
.function diff2(a, b) { var i, la = a.length, lb = b.length, res = []; if (!la) return b; else if (!lb) return a; for (i = 0; i < la; i++) { if (b.indexOf(a[i]) === -1) res.push(a[i]); } for (i = 0; i < lb; i++) { if (a.indexOf(b[i]) === -1) res.push(b[i]); } return res; }
Il existe une meilleure façon d'utiliser ES7:
Intersection
Car
[1,2,3] [2,3]
cela cédera[2,3]
. D'un autre côté, for[1,2,3] [2,3,5]
renverra la même chose.Différence
Car
[1,2,3] [2,3]
cela cédera[1]
. D'un autre côté, for[1,2,3] [2,3,5]
renverra la même chose.Pour une différence symétrique , vous pouvez faire:
De cette façon, vous obtiendrez un tableau contenant tous les éléments de arr1 qui ne sont pas dans arr2 et vice-versa
Comme @Joshaven Potter l'a souligné dans sa réponse, vous pouvez l'ajouter à Array.prototype afin qu'il puisse être utilisé comme ceci:
la source
< 0
plutôt que== -1
Array
différence est un soi-disantset operation
, car la recherche de propriété est le propre travail deSet
s, qui sont des ordres de grandeur plus rapides queindexOf
/includes
. Autrement dit, votre solution est très inefficace et plutôt lente.Set
, les valeurs doivent être uniques, non?[1,2,3] [2,3,5]
les chiffres sont uniques, mais si vous aviez dit[1,1,2,3] [1,2,3,5]
et attendu que[1]
vous ne pouviez pas utiliserSet
. Votre solution ne fonctionnerait pas non plus: - / J'ai fini par créer cette fonction parce que je ne pouvais pas trouver une manière satisfaisante de le faire de manière plus succincte. Si vous avez des idées sur la façon de le faire, j'aimerais savoir!Array.includes()
fonctionnalité ES7 n'est-elle pas au lieu de ES6? (1) (2) - et pour continuer, avec ES6, vous pourriezArray.some()
par exemple utiliserlet intersection = aArray.filter(a => bArray.some(b => a === b))
non?Afficher l'extrait de code
Remarque indexOf et filtre ne sont pas disponibles dans ie avant ie9.
la source
[1,2,3].diff([3,4,5])
elle reviendra[1,2]
au lieu de[1,2,4,5]
donc elle ne résout pas le problème dans la question d'origine, quelque chose à savoir.C'est de loin le moyen le plus simple d'obtenir exactement le résultat que vous recherchez, en utilisant jQuery:
diff
contient maintenant ce qui était dansold_array
ce n'est pasnew_array
la source
{a: 1} != {a: 1}
) ( preuve ).not
avec un tableau, jQuery utilise son utilitaire intégré.grep()
qui est spécifiquement destiné au filtrage des tableaux. Je ne vois pas cela changer.La méthode de différence dans Underscore (ou son remplacement direct , Lo-Dash ) peut également faire cela:
Comme avec n'importe quelle fonction Underscore, vous pouvez également l'utiliser dans un style plus orienté objet:
la source
JavaScript simple
Il existe deux interprétations possibles de "différence". Je vous laisse choisir celui que vous voulez. Dites que vous avez:
Si vous voulez l'obtenir
['a']
, utilisez cette fonction:Si vous voulez obtenir
['a', 'c']
(tous les éléments contenus dans l' una1
ou l' autrea2
, mais pas les deux - la soi-disant différence symétrique ), utilisez cette fonction:Lodash / Underscore
Si vous utilisez lodash, vous pouvez utiliser
_.difference(a1, a2)
(cas 1 ci-dessus) ou_.xor(a1, a2)
(cas 2).Si vous utilisez Underscore.js, vous pouvez utiliser la
_.difference(a1, a2)
fonction pour le cas 1.Set ES6, pour très grandes baies
Le code ci-dessus fonctionne sur tous les navigateurs. Cependant, pour les grands tableaux de plus d'environ 10 000 éléments, cela devient assez lent, car il a une complexité O (n²). Sur de nombreux navigateurs modernes, nous pouvons profiter de l'
Set
objet ES6 pour accélérer les choses. Lodash utilise automatiquementSet
lorsqu'il est disponible. Si vous n'utilisez pas lodash, utilisez l'implémentation suivante, inspirée du billet de blog d'Axel Rauschmayer :Remarques
Le comportement de tous les exemples peut être surprenant ou non évident si vous vous souciez des tableaux -0, +0, NaN ou clairsemés. (Pour la plupart des utilisations, cela n'a pas d'importance.)
la source
Pour obtenir la différence symétrique, vous devez comparer les tableaux dans les deux sens (ou dans tous les cas en cas de tableaux multiples)
ES7 (ECMAScript 2016)
ES6 (ECMAScript 2015)
ES5 (ECMAScript 5.1)
Exemple:
Différence entre les tableaux d'objets
Exemple:
la source
Une approche plus propre dans ES6 est la solution suivante.
Différence
Intersection
Union disjonctive (différence symétrique)
la source
a1 = ['a', 'b', 'e']
: e ne sera pas extrait.Vous pouvez utiliser un ensemble dans ce cas. Il est optimisé pour ce type d'opération (union, intersection, différence).
Assurez-vous qu'il s'applique à votre cas, une fois qu'il n'autorise aucun doublon.
la source
Set
fonction sans avoir à obtenir tout le reste ...Fusionnez les deux tableaux, les valeurs uniques n'apparaîtront qu'une seule fois, donc indexOf () sera le même que lastIndexOf ().
la source
pour soustraire un tableau d'un autre, utilisez simplement l'extrait ci-dessous:
Il retournera ['1,' 2 ',' 6 '] qui sont des éléments du premier tableau qui n'existent pas dans le second.
Par conséquent, selon votre exemple de problème, le code suivant est la solution exacte:
la source
Avec l'arrivée d'ES6 avec les sets et l'opérateur splat (au moment de ne fonctionner que dans Firefox, consultez le tableau de compatibilité ), vous pouvez écrire le liner suivant:
qui se traduira par
[ "c", "d" ]
.la source
b.filter(x => !a.indexOf(x)))
O(n + m)
votre solution estO(n * m)
où n et m sont des longueurs de tableaux. Prenez de longues listes et ma solution fonctionnera en quelques secondes, tandis que la vôtre prendra des heures.a.filter(x => !b1.has(x))
est plus simple. Et notez que la spécification nécessite uniquement que la complexité soitn * f(m) + m
enf(m)
sublinéaire en moyenne. C'est mieux quen * m
, mais pas nécessairementn + m
.var difference = [...new Set([...a].filter(x => !b1.has(x)))];
Pourquoi créez -vous un tableau 'a' en double? Pourquoi transformez-vous le résultat du filtre en un ensemble, puis de nouveau en tableau? N'est-ce pas l'équivalent devar difference = a.filter(x => !b1.has(x));
Approche fonctionnelle avec ES2015
Le calcul
difference
entre deux tableaux est l'une desSet
opérations. Le terme indique déjà que leSet
type natif doit être utilisé, afin d'augmenter la vitesse de recherche. Quoi qu'il en soit, il y a trois permutations lorsque vous calculez la différence entre deux ensembles:Voici une solution fonctionnelle qui reflète ces permutations.
Gauche
difference
:Droite
difference
:differencer
est trivial. C'est justedifferencel
avec des arguments inversés. Vous pouvez écrire une fonction pour plus de commodité:const differencer = flip(differencel)
. C'est tout!Symétrique
difference
:Maintenant que nous avons celui de gauche et de droite, l'implémentation du symétrique
difference
devient également triviale:Je suppose que cet exemple est un bon point de départ pour avoir une idée de ce que signifie la programmation fonctionnelle:
Programmation avec des blocs de construction qui peuvent être connectés de différentes manières.
la source
Une solution utilisant
indexOf()
sera correcte pour les petits tableaux mais à mesure qu'ils grandissent, les performances de l'algorithme se rapprochentO(n^2)
. Voici une solution qui fonctionnera mieux pour les très grands tableaux en utilisant des objets comme tableaux associatifs pour stocker les entrées du tableau sous forme de clés; il élimine également automatiquement les entrées en double mais ne fonctionne qu'avec des valeurs de chaîne (ou des valeurs qui peuvent être stockées en toute sécurité en tant que chaînes):la source
La réponse ci-dessus de Joshaven Potter est excellente. Mais il renvoie des éléments du tableau B qui ne sont pas dans le tableau C, mais pas l'inverse. Par exemple, si
var a=[1,2,3,4,5,6].diff( [3,4,5,7]);
alors il affichera: ==>[1,2,6]
, mais pas[1,2,6,7]
, quelle est la différence réelle entre les deux. Vous pouvez toujours utiliser le code de Potter ci-dessus mais simplement refaire la comparaison une fois en arrière aussi:Cela devrait produire:
[ 1, 2, 6, 7 ]
la source
Une autre façon de résoudre le problème
Vous pouvez également utiliser la syntaxe de la fonction flèche:
la source
la source
difference
comme fonction dans une future version et que cette fonction a alors une signature de fonction différente de la vôtre, elle cassera votre code ou les bibliothèques étrangères qui utilisent cette fonction.Solution très simple avec la fonction de filtrage de JavaScript:
la source
Que dis-tu de ça:
Donc, de cette façon, vous pouvez faire
array1.diff(array2)
pour obtenir leur différence (complexité horrible du temps pour l'algorithme - O (array1.length x array2.length) je crois)la source
En utilisant http://phrogz.net/JS/ArraySetMath.js, vous pouvez:
la source
cela fonctionne pour moi
la source
filter
)fn
Paramètre de rappel facultatif qui vous permet de spécifier comment comparer les éléments du tableaula source
length
valeurs. C'est déjà une propriété ordinaire. jsperf.com/array-length-cachingCela fonctionne: fusionnez essentiellement les deux tableaux, recherchez les doublons et placez ce qui n'est pas dupliqué dans un nouveau tableau, ce qui fait la différence.
la source
// approche es6
la source
Complexité symétrique et linéaire . Nécessite ES6.
la source
encore une autre réponse, mais il semble que personne n'ait mentionné jsperf où ils comparent plusieurs algorithmes et support technologique: https://jsperf.com/array-difference-javascript semble utiliser le filtre pour obtenir les meilleurs résultats. Merci
la source
Penser juste ... pour le plaisir ;-) est-ce que cela fonctionnerait ... (pour les tableaux de base de chaînes, de nombres, etc.) pas de tableaux imbriqués
Notez que le tri ne sera probablement pas comme indiqué ci-dessus ... mais si vous le souhaitez, appelez .sort () sur le tableau pour le trier.
la source
Je voulais une fonction similaire qui prenait un ancien tableau et un nouveau tableau et me donnait un tableau d'éléments ajoutés et un tableau d'éléments supprimés, et je voulais qu'elle soit efficace (donc pas de .contains!).
Vous pouvez jouer avec ma solution proposée ici: http://jsbin.com/osewu3/12 .
Quelqu'un peut-il voir des problèmes / améliorations à cet algorithme? Merci!
Liste des codes:
la source
Je cherchais une réponse simple qui n'impliquait pas l'utilisation de différentes bibliothèques, et j'ai trouvé la mienne qui, je pense, n'a pas été mentionnée ici. Je ne sais pas à quel point c'est efficace ou quoi que ce soit mais ça marche;
Pour mon code, j'ai également besoin de doublons, mais je suppose que ce n'est pas toujours préféré.
Je suppose que le principal inconvénient est qu'il compare potentiellement de nombreuses options qui ont déjà été rejetées.
la source
correction de petit bit pour la meilleure réponse
cela prendra en considération le type d'élément actuel. b / c lorsque nous créons un [a1 [i]], il convertit une valeur en chaîne à partir de sa valeur d'origine, nous avons donc perdu la valeur réelle.
la source