web-dev-qa-db-fra.com

JavaScript: Supprimer les doublons d'objets partageant la même valeur de propriété

J'ai un tableau d'objets que j'aimerais réduire en fonction d'une paire key:value spécifique. Je veux créer un tableau qui ne comprend qu'un seul objet par cette paire key:value spécifique. Peu importe quel objet des doublons est copié dans le nouveau tableau.

Par exemple, je souhaite couper en fonction de la propriété price de arrayWithDuplicates, en créant un nouveau tableau qui n'inclut qu'une seule de chaque valeur:

var arrayWithDuplicates = [
  {"color":"red", 
    "size": "small",
    "custom": {
      "inStock": true,
      "price": 10
    }
  },
  {"color":"green", 
    "size": "small",
    "custom": {
      "inStock": true,
      "price": 30
    }
  },
  {"color":"blue", 
    "size": "medium",
    "custom": {
      "inStock": true,
      "price": 30
    }
  },
  {"color":"red", 
    "size": "large",
    "custom": {
      "inStock": true,
      "price": 20
    }
  }
];

Deviendrait:

var trimmedArray = [
  {"color":"red", 
    "size": "small",
    "custom": {
      "inStock": true,
      "price": 10
    }
  },
  {"color":"green", 
    "size": "small",
    "custom": {
      "inStock": true,
      "price": 30
    }
  },
  {"color":"red", 
    "size": "large",
    "custom": {
      "inStock": true,
      "price": 20
    }
  }
];

Existe-t-il un JavaScript ou une fonction angulaire qui ferait une boucle et le ferait?

EDIT: La propriété à filtrer est imbriquée dans une autre propriété.

24
Lauren F

Vous pouvez utiliser underscore pour cela:

//by size:
var uSize = _.uniq(arrayWithDuplicates, function(p){ return p.size; });

//by custom.price;
var uPrice = _.uniq(arrayWithDuplicates, function(p){ return p.custom.price; });
4
user3335966
function removeDuplicatesBy(keyFn, array) {
  var mySet = new Set();
  return array.filter(function(x) {
    var key = keyFn(x), isNew = !mySet.has(key);
    if (isNew) mySet.add(key);
    return isNew;
  });
}

utilisation (les fonctions de flèche d'EcmaScript6 améliorent l'apparence):

removeDuplicatesBy(x => x.custom.price, yourArrayWithDuplicates);

EDIT: extrait modifié pour ne pas utiliser le nom de la propriété, mais pour utiliser une fonction de sélecteur de clé, afin que vous puissiez accéder aux propriétés imbriquées.

23
Tamas Hegedus

Je ne pense pas qu'il existe une fonction intégrée dans Angular, mais il n'est pas difficile d'en créer une:

function removeDuplicates(originalArray, objKey) {
  var trimmedArray = [];
  var values = [];
  var value;

  for(var i = 0; i < originalArray.length; i++) {
    value = originalArray[i][objKey];

    if(values.indexOf(value) === -1) {
      trimmedArray.Push(originalArray[i]);
      values.Push(value);
    }
  }

  return trimmedArray;

}

Utilisation:

removeDuplicates(arrayWithDuplicates, 'size');

Résultats:

[
    {
        "color": "red",
        "size": "small"
    },
    {
        "color": "blue",
        "size": "medium"
    },
    {
        "color": "red",
        "size": "large"
    }
]

Et

removeDuplicates(arrayWithDuplicates, 'color');

Résultats:

[
    {
        "color": "red",
        "size": "small"
    },
    {
        "color": "green",
        "size": "small"
    },
    {
        "color": "blue",
        "size": "medium"
    }
]
12
yvesmancera

Utilisez Array.filter(), en gardant une trace des valeurs en utilisant une Object comme hachage et en filtrant les éléments dont la valeur est déjà contenue dans le hachage.

function trim(arr, key) {
    var values = {};
    return arr.filter(function(item){
        var val = item[key];
        var exists = values[val];
        values[val] = true;
        return !exists;
    });
}
7
gilly3

Vous pouvez utiliser lodash pour supprimer les objets en double:

 import * as _ from 'lodash';
  _.uniqBy(data, 'id');

Ici 'id' est votre identifiant unique 

2
Mukesh Ranjan
for (let i = 0; i < arrayWithDuplicates.length; i++) {
     for (let j = i + 1; j < arrayWithDuplicates.length; j++) {
       if (arrayWithDuplicates[i].name === students[j].name) {
          arrayWithDuplicates.splice(i, 1);
       }
     }
    }

this will work perfectly...and this will delete first repeated array.
To delete last repeated array we only have to change
 arrayWithDuplicates.splice(i, 1) ; into
 arrayWithDuplicates.splice(j, 1);
1
sudha priya

Solution simple mais pas la plus performante:

var unique = [];
duplicates.forEach(function(d) {
    var found = false;
    unique.forEach(function(u) {
        if(u.key == d.key) {
            found = true;
        }
    });
    if(!found) {
        unique.Push(d);
    }
});
1
Souvik Basu

en utilisant lodash, vous pouvez le filtrer facilement

le premier paramètre sera votre tableau et le second sera votre champ avec les doublons

_.uniqBy(arrayWithDuplicates, 'color')

il retournera un tableau avec une valeur unique 

1
yureka

Essayez la fonction suivante:

function trim(items){
    const ids = [];
    return items.filter(item => ids.includes(item.id) ? false : ids.Push(item.id));
}
0
sliter

De prime abord, aucune fonction ne le fera pour vous car vous traitez avec un tableau d'objets et il n'y a pas non plus de règle pour laquelle les doublons seraient supprimés comme doublons.

Dans votre exemple, vous supprimez celui avec size: small, mais si vous deviez l'implémenter à l'aide d'une boucle, vous incluriez probablement le premier et excluiez le dernier lorsque vous parcourez votre tableau.

Il peut être intéressant de regarder une bibliothèque telle que lodash et de créer une fonction qui utilise une combinaison de ses méthodes d’API pour obtenir le comportement souhaité.

Voici une solution possible que vous pourriez utiliser en utilisant des tableaux de base et une expression de filtre pour vérifier si un nouvel élément serait considéré comme un doublon avant d’être attaché à un résultat renvoyé.

var arrayWithDuplicates = [
    {"color":"red", "size": "small"},
    {"color":"green", "size": "small"},
    {"color":"blue", "size": "medium"},
    {"color":"red", "size": "large"}
];

var reduce = function(arr, prop) {
  var result = [],
      filterVal,
      filters,
      filterByVal = function(n) {
          if (n[prop] === filterVal) return true;
      };
  for (var i = 0; i < arr.length; i++) {
      filterVal = arr[i][prop];
      filters   = result.filter(filterByVal);
      if (filters.length === 0) result.Push(arr[i]);
  }
  return result;
};

console.info(reduce(arrayWithDuplicates, 'color'));

Vous pouvez consulter des ouvrages sur le filtrage des tableaux ici Si vous devez indiquer une préférence sur l'élément à supprimer, vous pouvez définir des paramètres et une logique supplémentaires permettant d'effectuer des contrôles de propriété supplémentaires avant d'ajouter une valeur de retour.

J'espère que cela pourra aider!

0
jh3y

Voici la méthode TypeScript

    public removeDuplicates(originalArray:any[], prop) {
    let newArray = [];
    let lookupObject = {};

    originalArray.forEach((item, index) => {
        lookupObject[originalArray[index][prop]] = originalArray[index];
    });

    Object.keys(lookupObject).forEach(element => {
        newArray.Push(lookupObject[element]);
    });
    return newArray;
}

Et

let output = this.removeDuplicates(yourArray,'color');
0
Praveen M P

Ceci est juste une autre 'fonctionnalité' basée sur la solution de yvesmancera (après que j'ai commencé à bricoler pour ma propre solution). Nous avons également noté que nous ne sommes autorisés à utiliser que IE 11, une version limitée de ES5 est donc autorisée.

var newArray = RemoveDuplicates(myArray,'Role', 2);

function RemoveDuplicates(array, objKey, rtnType) {
var list = [], values = [], value;
for (var i = 0; i < array.length; i++) {
    value = array[i][objKey];
    if(values.indexOf(value) === -1){
        list.Push(array[i]);
        values.Push(value);
        }
    }
    if(rtnType == 1)
        return list;
    return values;
};

En espérant que cela fonctionnera pour la plupart des tableaux, sinon pour tous, lors du filtrage des objets en fonction d'une valeur de propriété d'objet unique.

0
Keltanis