web-dev-qa-db-fra.com

Supprimer les objets en double du tableau JSON

J'ai un tableau qui ressemble à ceci:

var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];

Et je dois enlever les doublons pour qu'il en reste quelque chose:

var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];

J'ai essayé d'installer underscore.js et d'utiliser ._uniq, mais cela ne semble fonctionner que lorsqu'un seul couple key:value apparaît dans l'objet. Je n'arrive pas à le faire fonctionner avec plusieurs clés. 

Quand j'essaie quelque chose comme:

var uniqueStandards = _.uniq(standardsList, function(item, key, Domain){
    return item.Domain;
});

Je ne reçois que les trois premières valeurs uniques (une par classe). Mais j'ai besoin de toutes les valeurs uniques à la fois par classe et par domaine. Existe-t-il un moyen simple d’alimenter les deux touches de la fonction _.uniq?

En fin de compte, j'ai besoin d'une liste avec chaque note unique en tant qu'en-tête et les domaines uniques en tant qu'éléments de liste à transmettre à une page HTML. Je me trompe peut-être, alors s’il existe un moyen plus facile d’atteindre cet objectif final, je suis ouvert aux idées. 

Merci d'avance!

Edit: Obtenir de bonnes réponses et je voulais clarifier quel était mon objectif final. J'essaie de créer une série de listes en HTML de la forme:

<div>
    <h3>Math K</h3>
    <li>Counting & Cardinality</li>
    <li>Geometry</li>
</div>
<div>
    <h3>Math 1</h3>
    <li>Counting & Cardinality</li>
    <li>Orders of Operation</li>
</div>
<div>
    <h3>Math 2</h3>
    <li>Geometry</li>
</div>

Mon objectif initial était toutefois de créer un tableau et de l'insérer dans l'élément <div> de la page avec $("#divid").append(array).

27
dchess

En fin de compte, j'ai besoin d'une liste avec chaque note unique en tant qu'en-tête et les domaines uniques en tant qu'éléments de liste à transmettre à une page HTML. Je me trompe peut-être, alors s’il existe un moyen plus facile d’atteindre cet objectif final, je suis ouvert aux idées.

Donc, vous n'avez pas réellement besoin de ce tableau de sortie dans le format que vous avez demandé.

Dans ce cas, je me mettrais directement au chasse avec une solution très simple et efficace:

var grades = {};
standardsList.forEach( function( item ) {
    var grade = grades[item.Grade] = grades[item.Grade] || {};
    grade[item.Domain] = true;
});

console.log( JSON.stringify( grades, null, 4 ) );

L'objet grades résultant est:

{
    "Math K": {
        "Counting & Cardinality": true,
        "Geometry": true
    },
    "Math 1": {
        "Counting & Cardinality": true,
        "Orders of Operation": true
    },
    "Math 2": {
        "Geometry": true
    }
}

Une chose intéressante à propos de cette approche est qu’elle est très rapide. Notez que cela ne fait qu'un seul passage dans le tableau d'entrée, contrairement à d'autres solutions qui nécessitent plusieurs passages (que vous les écriviez vous-même ou que _.uniq() le fasse pour vous). Cela n’aura pas d’importance pour un petit nombre d’articles, mais il est bon de garder à l’esprit les listes plus volumineuses.

Et avec cet objet, vous avez maintenant tout ce dont vous avez besoin pour exécuter du code ou générer tout autre format de votre choix. Par exemple, si vous avez besoin du format de sortie de tableau exact que vous avez mentionné, vous pouvez utiliser:

var outputList = [];
for( var grade in grades ) {
    for( var domain in grades[grade] ) {
        outputList.Push({ Grade: grade, Domain: domain });
    }
}

JSON.stringify( outputList, null, 4 );

Cela va enregistrer:

[
    {
        "Grade": "Math K",
        "Domain": "Counting & Cardinality"
    },
    {
        "Grade": "Math K",
        "Domain": "Geometry"
    },
    {
        "Grade": "Math 1",
        "Domain": "Counting & Cardinality"
    },
    {
        "Grade": "Math 1",
        "Domain": "Orders of Operation"
    },
    {
        "Grade": "Math 2",
        "Domain": "Geometry"
    }
]

Rai demande dans un commentaire comment cette ligne de code fonctionne:

var grade = grades[item.Grade] = grades[item.Grade] || {};

C'est un idiome courant pour récupérer une propriété d'objet ou fournir une valeur par défaut si la propriété est manquante. Notez que les assignations = sont effectuées dans un ordre de droite à gauche. Nous pourrions donc le traduire littéralement en utilisant une instruction if et une variable temporaire:

// Fetch grades[item.Grade] and save it in temp
var temp = grades[item.Grade];
if( ! temp ) {
    // It was missing, so use an empty object as the default value
    temp = {};
}
// Now save the result in grades[item.Grade] (in case it was missing)
// and in grade
grades[item.Grade] = temp;
var grade = temp;

Vous remarquerez peut-être que dans le cas où grades[item.Grade] existe déjà, nous prenons la valeur que nous venons d'extraire et la stockons dans la même propriété. Ceci est inutile, bien sûr, et vous ne le feriez probablement pas si vous écriviez le code de cette façon. Au lieu de cela, vous le simplifieriez:

var grade = grades[item.Grade];
if( ! grade ) {
    grade = grades[item.Grade] = {};
}

Ce serait un moyen parfaitement raisonnable d’écrire le même code, mais c’est aussi plus efficace. Cela vous donne également le moyen de faire un test plus spécifique que la "véracité" sur laquelle repose l'idiome ||. Par exemple, au lieu de if( ! grade ), vous voudrez peut-être utiliser if( grade === undefined ).

12
Michael Geary
function arrUnique(arr) {
    var cleaned = [];
    arr.forEach(function(itm) {
        var unique = true;
        cleaned.forEach(function(itm2) {
            if (_.isEqual(itm, itm2)) unique = false;
        });
        if (unique)  cleaned.Push(itm);
    });
    return cleaned;
}

var standardsList = arrUnique(standardsList);

FIDDLE

Cela va retourner

var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];

Quel est exactement ce que vous avez demandé?

21
adeneo

Je sais qu'il existe déjà de nombreuses réponses, mais la meilleure solution pour une structure complexe de JSON est la suivante:

var arr = [{ "State": "RWCW", "desc": "WEST", "code": "RWCW", "level": 0, "save": "RWCW : WEST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RCSW", "desc": "SOUTHWEST", "code": "RCSW", "level": 0, "save": "RCSW : SOUTHWEST", "attribute1": "", "attribute2": "" }, { "State": "RECW", "desc": "NORTHEAST", "code": "RECW", "level": 0, "save": "RECW : NORTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RWCW", "desc": "WEST", "code": "RWCW", "level": 0, "save": "RWCW : WEST", "attribute1": "", "attribute2": "" }, { "State": "RWCW", "desc": "WEST", "code": "RWCW", "level": 0, "save": "RWCW : WEST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RCSW", "desc": "SOUTHWEST", "code": "RCSW", "level": 0, "save": "RCSW : SOUTHWEST", "attribute1": "", "attribute2": "" }, { "State": "RECW", "desc": "NORTHEAST", "code": "RECW", "level": 0, "save": "RECW : NORTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RWCW", "desc": "WEST", "code": "RWCW", "level": 0, "save": "RWCW : WEST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RECW", "desc": "NORTHEAST", "code": "RECW", "level": 0, "save": "RECW : NORTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RWCW", "desc": "WEST", "code": "RWCW", "level": 0, "save": "RWCW : WEST", "attribute1": "", "attribute2": "" }, { "State": "RCSW", "desc": "SOUTHWEST", "code": "RCSW", "level": 0, "save": "RCSW : SOUTHWEST", "attribute1": "", "attribute2": "" }, { "State": "RWCW", "desc": "WEST", "code": "RWCW", "level": 0, "save": "RWCW : WEST", "attribute1": "", "attribute2": "" }, { "State": "RCNW", "desc": "MIDWEST", "code": "RCNW", "level": 0, "save": "RCNW : MIDWEST", "attribute1": "", "attribute2": "" }, { "State": "RCSW", "desc": "SOUTHWEST", "code": "RCSW", "level": 0, "save": "RCSW : SOUTHWEST", "attribute1": "", "attribute2": "" }, { "State": "RECW", "desc": "NORTHEAST", "code": "RECW", "level": 0, "save": "RECW : NORTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RCNW", "desc": "MIDWEST", "code": "RCNW", "level": 0, "save": "RCNW : MIDWEST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RECW", "desc": "NORTHEAST", "code": "RECW", "level": 0, "save": "RECW : NORTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RCNW", "desc": "MIDWEST", "code": "RCNW", "level": 0, "save": "RCNW : MIDWEST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RCNW", "desc": "MIDWEST", "code": "RCNW", "level": 0, "save": "RCNW : MIDWEST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RECW", "desc": "NORTHEAST", "code": "RECW", "level": 0, "save": "RECW : NORTHEAST", "attribute1": "", "attribute2": "" }];

var clean = arr.filter((arr, index, self) =>
    index === self.findIndex((t) => (t.save === arr.save && t.State === arr.State)))

console.log(clean);

Vous pouvez essayer ceci directement sur la console du navigateur Chrome et l’éditer en fonction de vos besoins.

J'espère que ça aidera quelqu'un.

8
Aarchie

Je reviens à une vieille question, mais je voulais publier une itération sur la réponse de @ adeneo. Cette réponse est tout à fait générale, mais dans ce cas d'utilisation, elle pourrait être plus efficace (c'est lent sur ma machine avec un tableau de quelques milliers d'objets). Si vous connaissez les propriétés spécifiques des objets à comparer, comparez-les directement:

var sl = standardsList;
var out = [];

for (var i = 0, l = sl.length; i < l; i++) {
    var unique = true;
    for (var j = 0, k = out.length; j < k; j++) {
        if ((sl[i].Grade === out[j].Grade) && (sl[i].Domain === out[j].Domain)) {
            unique = false;
        }
    }
    if (unique) {
        out.Push(sl[i]);
    }
}

console.log(sl.length); // 10
console.log(out.length); // 5
7
James Irwin

Solution javascript pour votre cas:

console.log(unique(standardsList));

function unique(obj){
    var uniques=[];
    var stringify={};
    for(var i=0;i<obj.length;i++){
       var keys=Object.keys(obj[i]);
       keys.sort(function(a,b) {return a-b});
       var str='';
        for(var j=0;j<keys.length;j++){
           str+= JSON.stringify(keys[j]);
           str+= JSON.stringify(obj[i][keys[j]]);
        }
        if(!stringify.hasOwnProperty(str)){
            uniques.Push(obj[i]);
            stringify[str]=true;
        }
    }
    return uniques;
}
5
juvian

Ce qui suit fonctionne pour moi:

_.uniq(standardsList, JSON.stringify)

Ce serait probablement lent pour les très longues listes, cependant.

3
stubailo

** La méthode suivante fait comme vous voulez. Il filtre le tableau en fonction de toutes les valeurs de propriétés . **

    var standardsList = [
  { "Grade": "Math K", "Domain": "Counting & Cardinality" },
  { "Grade": "Math K", "Domain": "Counting & Cardinality" },
  { "Grade": "Math K", "Domain": "Counting & Cardinality" },
  { "Grade": "Math K", "Domain": "Counting & Cardinality" },
  { "Grade": "Math K", "Domain": "Geometry" },
  { "Grade": "Math 1", "Domain": "Counting & Cardinality" },
  { "Grade": "Math 1", "Domain": "Counting & Cardinality" },
  { "Grade": "Math 1", "Domain": "Orders of Operation" },
  { "Grade": "Math 2", "Domain": "Geometry" },
  { "Grade": "Math 2", "Domain": "Geometry" }
];

const removeDupliactes = (values) => {
  let concatArray = values.map(eachValue => {
    return Object.values(eachValue).join('')
  })
  let filterValues = values.filter((value, index) => {
    return concatArray.indexOf(concatArray[index]) === index

  })
  return filterValues
}
removeDupliactes(standardsList) 

Résultats ceci

[{Grade: "Math K", Domain: "Counting & Cardinality"}

{Grade: "Math K", Domain: "Geometry"}

{Grade: "Math 1", Domain: "Counting & Cardinality"}

{Grade: "Math 1", Domain: "Orders of Operation"}

{Grade: "Math 2", Domain: "Geometry"}] 
2
saiteja

J'avais besoin de faire un peu de duping avec des objets JSON alors je suis tombé sur cette page. Cependant, je suis allé avec la solution courte ES6 (pas besoin de bibliothèques externes), en l'exécutant dans des extraits de Chrome Dev Tools:

const data = [ /* any list of objects */ ];
const set = new Set(data.map(item => JSON.stringify(item)));
const dedup = [...set].map(item => JSON.parse(item));
console.log(`Removed ${data.length - dedup.length} elements`);
console.log(dedup);
2
Nomaed
var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];          

 function uniqurArray(array){
                         var a = array.concat();
                        for(var i=0; i<a.length; i++) {
                            for(var j=i+1; j<a.length; j++) {
                                if(a[i].Grade === a[j].Grade){
                                    a.splice(j--, 1);
                                }
                            }
                        }

                        return a;
                    }

    uniqurArray(standardsList) // put this js in console and you get uniq object in array
1
shehzad lakhani

var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];

standardsList = standardsList.filter((li, idx, self) => self.map(itm => itm.Domain).indexOf(li.Domain) === idx)

document.write(JSON.stringify(standardsList))

voici une façon fonctionnelle de le faire qui est beaucoup plus facile

standardsList = standardsList.filter((li, idx, self) => self.map(itm => itm.domain).indexOf(li.domain) === idx)
0
Miguel Coder

Utilisez ce pseudocode

var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];
var newArr =[]
for(var i in standardsList){
    newArr.Push(JSON.stringify(standardsList[i]))
}
var obj = {};
newArr= newArr.filter((item)=>{
    return obj.hasOwnProperty(item) ? false : (obj[item] = true);
})
standardsList.length = 0
for(var i in newArr){
    standardsList.Push(JSON.parse(newArr[i]))
}
console.log(standardsList)

J'ai choisi un exemple de tableau similaire au vôtre. Il est plus facile de comparer des objets une fois que vous les avez enchaînés. Ensuite, il vous suffit de comparer les chaînes.

0
ashish yadav