web-dev-qa-db-fra.com

Créer un tableau d'objets uniques par propriété

J'ai créé un tableau d'objets comme suit:

var places = [];
var a = {};
a.lat = 12.123;
a.lng = 13.213;
a.city = "New York";

places.Push(a);

var b = {};
b.lat = 3.123;
b.lng = 2.213;
b.city = "New York";

places.Push(b);

...

J'essaye de créer un nouveau tableau qui filtre les lieux pour ne contenir que des objets qui n'ont pas la même propriété city (les doublons lat/lng sont ok). Existe-t-il une fonction JS ou Jquery intégrée pour y parvenir? 

24
theblueone

Le plus court, mais pas la meilleure performance (voir mise à jour ci-dessous) solution pour es6:

function unique(array, propertyName) {
   return array.filter((e, i) => array.findIndex(a => a[propertyName] === e[propertyName]) === i);
}

performances: https://jsperf.com/compare-unique-array-by-property

16
IgorL

Ma suggestion :

Array.prototype.uniqueCity = function() {
    var processed = [];
    for (var i=this.length-1; i>=0; i--){
        if (processed.indexOf(this[i].city)<0) {
            processed.Push(this[i].city);
        } else {
            this.splice(i, 1);
        }
    }
}

utilisé :

places.uniqueCity();

ou

Array.prototype.uniqueObjectArray = function(field) {
    var processed = [];
    for (var i=this.length-1; i>=0; i--) {
        if (this[i].hasOwnProperty(field)) {
            if (processed.indexOf(this[i][field])<0) {
                processed.Push(this[i][field]);
            } else {
                this.splice(i, 1);
            }
        }
    }
}

places.uniqueObjectArray('city');

Avec ce qui précède, vous pouvez trier le tableau en fonction de n’importe lequel des champs des objets, même s’ils ne sont pas présents pour certains des objets .

ou

function uniqueCity(array) {
    var processed = [];
    for (var i=array.length-1; i>=0; i--){
        if (processed.indexOf(array[i].city)<0) {
            processed.Push(array[i].city);
        } else {
            array.splice(i, 1);
        }
    }
    return array;
}

places = uniqueCity(places);
4
davidkonrad

https://lodash.com/docs#uniqBy

https://github.com/lodash/lodash/blob/4.13.1/lodash.js#L7711

/**
 * This method is like `_.uniq` except that it accepts `iteratee` which is
 * invoked for each element in `array` to generate the criterion by which
 * uniqueness is computed. The iteratee is invoked with one argument: (value).
 *
 * @static
 * @memberOf _
 * @since 4.0.0
 * @category Array
 * @param {Array} array The array to inspect.
 * @param {Array|Function|Object|string} [iteratee=_.identity]
 *  The iteratee invoked per element.
 * @returns {Array} Returns the new duplicate free array.
 * @example
 *
 * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
 * // => [2.1, 1.2]
 *
 * // The `_.property` iteratee shorthand.
 * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
 * // => [{ 'x': 1 }, { 'x': 2 }]
 */
3
Alec Perkey

J'ai développé un peu la solution @IgorL, mais j'ai étendu le prototype et lui a donné une fonction de sélecteur au lieu d'une propriété pour la rendre un peu plus flexible:

Array.prototype.unique = function(selector) {
   return this.filter((e, i) => this.findIndex((a) => {
      if (selector) {
        return selector(a) === selector(e);
      }
      return a === e;
    }) === i);
};

Utilisation:

// with no param it uses strict equals (===) against the object
let primArr = ['one','one','two','three','one']
primArr.unique() // ['one','two','three']

let a = {foo:123}
let b = {foo:123}
let fooArr = [a,a,b]
fooArr.unique() //[a,b]

// alternatively, you can pass a selector function
fooArr.unique(item=>item.foo) //[{foo:123}] (first "unique" item returned)

Ce n'est certainement pas la manière la plus performante de le faire, mais tant que le sélecteur est simple et que le tableau n'est pas énorme, cela devrait fonctionner correctement.

Dans TypeScript

Array.prototype.unique = function<T>(this: T[], selector?: (item: T) => object): T[] {
   return this.filter((e, i) => this.findIndex((a) => {
      if (selector) {
        return selector(a) === selector(e);
      }
      return a === e;
    }) === i);
};
3
NSjonas
var places = [];
var a = {};
a.lat = 12.123;
a.lng = 13.213;
a.city = "New York";

places.Push(a);

var b = {};
b.lat = 3.123;
b.lng = 2.213;
b.city = "New York";

places.Push(b);

getUniqAR(places,'city'); //Return Uniq Array by property

function getUniqAR(Data,filter){
var uniar =[];
Data.forEach(function(item,ind,arr){
    var dupi=false;
    if(!uniar.length) uniar.Push(item) //Push first obj into uniq array 
    uniar.forEach(function(item2, ind2,arr){
    if(item2[filter] == item[filter]){  //check each obj prop of uniq array 
      dupi=true; //if values are same put duplicate is true
        }     
    })
if(!dupi){  uniar.Push(item)} //if no duplicate insert to uniq

})
console.log(uniar)
return uniar;
}
1
pandian_Snkl

Comme indiqué dans les commentaires, vous pouvez utiliser un objet comme une carte, ce qui vous permettra d'éviter les doublons. Vous pouvez ensuite énumérer les propriétés de l'objet.

travail de violon: http://jsfiddle.net/gPRPQ/1/

var places = [];
var a = {};
a.lat = 12.123;
a.lng = 13.213;
a.city = "New York";

places.Push(a);

var b = {};
b.lat = 3.123;
b.lng = 2.213;
b.city = "New York";

places.Push(b);

var unique = {}

for (var i = 0; i < places.length; i++) {
    var place = places[i];
    unique[place.city] = place;
}

for (var name in unique) {
    var place = unique[name];
    console.log(place);
}
1
Robert Byrne

Vous pouvez utiliser une carte pour que les entrées avec la même propriété de clé (dans votre cas, "ville") n'apparaissent qu'une fois.

module.exports = (array, prop) => {
   const keyValueArray = array.map(entry => [entry[prop], entry]);
   const map = new Map(keyValueArray);
   return Array.from(map.values());
};

Plus d'infos sur la carte et les objets de tableaux ici

Exemple de base sur Codepen

0
Tamo Maes

Une autre option:

const uniqueBy = prop => list => {
    const uniques = {}
    return list.reduce(
        (result, item) => {
            if (uniques[item[prop]]) return result
            uniques[item[prop]] = item
            return [...result, item]
        },
        [],
    )
}

const uniqueById = uniqueBy('id')

uniqueById([
    { id: 1, name: 'one' },
    { id: 2, name: 'two' },
    { id: 1, name: 'one' },
    { id: 3, name: 'three' }
])

Vous pouvez le coller sur votre console pour le voir fonctionner… .. Il devrait fonctionner pour le scénario présenté et quelques autres.

0
rafaelbiten