7
votes

Supprimer des objets équivalents mais uniques d'un tableau JavaScript

J'ai un éventail d'objets similaires à ceux suivants:

for(var i = 0, numRoutes = routeArr.length; i < numRoutes; i++) {
    var primaryRoute = routeArr[i];

    for(var j = 0; j < numRoutes; j++) {
        var secondRoute = routeArr[j];

        if(primaryRoute.start === secondRoute.end && primaryRoute.end === secondRoute.start) {
            routeArr.splice(j, 1);
            continue;
        }
    }
}


2 commentaires

La manière habituelle de faire cela est la suivante: Triez-la d'abord (dans votre cas, vous devez inverser le début et la fin si (Fin> Démarrer)). Ensuite, les lignes en double seront exactement les mêmes. Alors juste une boucle pour enlever la duplicate


Lorsque vous retirez un élément de matrice, ne courez jamais une boucle de 0 à longueur. Ce n'est pas en sécurité car après le déménagement, vous devez ajuster vos indices. Meilleure boucle d'exécution dans l'ordre décroissant I.e. De longueur-1 à 0, cela fonctionnera au cas où vous allez supprimer un élément de matrice et ne reviendra jamais des éléments avec des indices plus gros. De plus, votre instruction IF ne vérifie qu'une seule condition d'être une ligne identique, vous devez également ajouter d'autres contrôles avec ou une déclaration.


5 Réponses :


3
votes

Créer un objet / carte en JavaScript et conservez les index des objets uniques, stockez "Min (Démarrer, fin): max (Démarrer, fin)" En tant que clé et index comme valeur. Voici une implémentation de votre question dans JavaScript:

// your initial array
var routeArr = [
    {start: 1, end: 2},
    {start: 1, end: 3},
    {start: 1, end: 4},
    {start: 2, end: 1},
    {start: 3, end: 1},
    {start: 4, end: 1}
];

// map where we will store key => value where key is a joined start,end of your array's item and value is an item index 
var keyToRouteIndexMap = {};

for (var i in routeArr){
    // calculating min and max from start and end to understand {start:1, end:2} and {start:2, end:1} object as duplicates
    var min = Math.min(routeArr[i].start,routeArr[i].end);
    var max = Math.max(routeArr[i].start,routeArr[i].end);
    // unique key 
    var key = min+':'+max;
    if (!keyToRouteIndexMap.hasOwnProperty(key)){
        keyToRouteIndexMap[key] = i;
    }
}

for(var key in keyToRouteIndexMap){
    if(keyToRouteIndexMap.hasOwnProperty(key)){
        console.log(routeArr[keyToRouteIndexMap[key]]);
    }
}


6 commentaires

Notez que si vous utilisez ES6, vous pouvez plutôt utiliser L'objet Set


Il y a aussi quelques implémentations JavaScript construites pour imiter HashSetsets: github.com/timdown/jshashable


@HAMMS: Comment l'objet défini pourrait-il aider? Il ne compare que des références d'objet.


@Vahan Simonyan: Vous devriez probablement vérifier pour HASOWNPROPERTY () lors de l'itération des touches d'objet.


@LE_M Merci, pour un commentaire utile (j'ai édité la réponse).


@LE_M Vous ne pouviez évidemment pas utiliser les objets eux-mêmes comme des éléments de l'ensemble, mais vous pouvez construire une clé de la même manière que cet exemple est et simplement le mettre dans un ensemble plutôt que de réaffecter un objet pour servir de jeu.



2
votes

Voici une solution générale au problème de la suppression des valeurs dupliquées à partir de matrices JavaScript: xxx pré>

appliqué à votre roulemearr code>: p>

var routeArr = [
    {start: 1, end: 2},
    {start: 1, end: 3},
    {start: 1, end: 4},
    {start: 2, end: 1},
    {start: 3, end: 1},
    {start: 4, end: 1}
];

routeArr = uniquify(routeArr, function(route) {
    return route.start < route.end ? '' + route.start + ':' + route.end : '' + route.end + ':' + route.start;
});


1 commentaires

Je suppose que la fonction de la fonction de rappel {Démarrer: 2, Fin: 3} et {Démarrer: 6, Fin: 1} au même emplacement.



2
votes

Vous pouvez faire comme ça. Je suppose que cela est très rapide car il n'y a pas de recherches du tout. One Array.Prototype.Ruce () Fonctionnement () Pour construire à la fois la table de hachage (table de recherche) et l'objet réduit en même temps. Ensuite, mapper les touches d'objet pour obtenir le résultat. Ici, c'est;

p>

var routeArr = [
    {start: 1, end: 2},
    {start: 1, end: 3},
    {start: 1, end: 4},
    {start: 2, end: 1},
    {start: 3, end: 1},
    {start: 4, end: 1}
],

     reduced = routeArr.reduce((p,c) => {!(p[c.start+"-"+c.end]  ||
                                           p[c.end+"-"+c.start]) &&
                                          (p[c.start+"-"+c.end] = true,
                                           p.result.push(c));
                                           return p;
                                        },{"result":[]});
console.log(reduced.result);


3 commentaires

Belle solution fonctionnelle. Maintenant, j'aimerais vraiment voir une comparaison de performance avec les approches non fonctionnelles.


Je pense maintenant que vous le dépassez un peu avec le code-minification. Chocher des noms de variable auto-documentant et ne pas mettre en place des affectations dans des comparaisons pourrait aider à mieux comprendre votre belle solution :)


@Le_m oui je suppose que vous pourriez avoir raison. Je vais mettre quelques explications ci-dessous. Pour moi, cela ressemble à un poème cependant. :)



1
votes

J'ai écrit la fonction ci-dessous pour le faire soigneusement xxx


2 commentaires

Ceci est inefficace de manière opérationnelle. Cela vous oblige à évaluer chaque paire plusieurs fois. Si vous augmentez la longueur de la routiche à 19 par exemple, 189 évaluations sont effectuées. La carte semble être une approche plus propre. En Java, une HASHMAP serait une excellente structure de données pour ce type de mise en œuvre. GITUB.COM/JSHASHTABLE est une implémentation de hashSet en JavaScript.


Les objets JavaScript offrent déjà une implémentation «HASHMAP», le seul problème est que les touches ne peuvent pas être des objets - vous avez donc besoin d'une fonction «hachage» soit par une cartographie générale d'objets à hachage (votre lien) qui est inefficace comme vous auriez besoin de l'inefficace. à travers la chaîne de prototype ou par une fonction fournie par l'utilisateur plus performant.



2
votes

Votre méthodologie de boucle imbriquée est 'laid'- Mais ce n'est pas votre problème.

Vos erreurs de mise en œuvre résultent du fait que les deux pour vos boucles supposent que la structure de la matrice ne changera pas comme vous la mutateur, ce qui vous fait sauter sur certains éléments de le tableau. p>

'I' et 'J' sont des incrémenters «stupides» - que pour la boucle ne raconte pas au code d'aller à l'élément suivant de la matrice avec chaque itération, il le dit d'aller à (tableau [last_index_i_uced + 1] code> - Donc, lorsque vous épissez quelque chose, le tableau Vous envisagez des modifications et que le point suivant est passé sur la ligne. P>

Je vois beaucoup de fantaisie Méthodes de tableau et des suggestions ES6, mais je suppose de votre question que vous êtes toujours un peu nouveau à JS et que vous pourriez utiliser des fondamentaux de la construction de temps (aucune infraction prévue). p>

Essayez une fonction de décrétation récursive: P>

function uniquify(inputArray, ind){
    var checkStart = inputArray[ind].start, checkEnd =inputArray[ind].end
    for (var i=(ind-1);i > -1; --i){
        var thisStart = inputArray[i].start, thisEnd = inputArray[i].end
        if ((thisStart == checkStart || thisStart == checkEnd) && (thisEnd == checkStart || thisEnd == checkEnd)){

            inputArray.splice(i,1)
        }
    }

    --ind
    if (ind > -1){
        uniquify(inputArray,ind)
    }
}
uniquify(routeArr,routeArr.length -1);


3 commentaires

Je recommande d'utiliser des points-virgules partout même s'ils ne sont pas toujours nécessaires dans JS. En outre, votre index de boucle I est une variable globale, mieux la rendre locale avec Var.


Vous avez raison de supposer que je suis nouveau à JS, au moins dans un projet de cette taille. Longue histoire courte, nous réécrivons une ancienne application C ++ pour fonctionner sur iPad et Android. La décision a été prise d'utiliser HTML5 et JavaScript avec CORDOVA (que j'ai pris en charge au début, mais j'ai maintenant mes doutes sur). Malheureusement, certaines décisions de conception ont été effectuées dans la version précédente C ++ qui nous oblige à travailler avec les données de la demande de manière non conventionnelle. J'essaie de trouver une solution élégante et efficace. Merci pour votre réponse, je l'essaie que nous parlons.


@LE_M - Merci d'avoir attrapé le manque de var dans ma boucle. Édité pour réparer.