webentwicklung-frage-antwort-db.com.de

Erstellen Sie ein Array eindeutiger Objekte nach Eigenschaft

Ich habe ein Array von Objekten so erstellt:

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);

...

Ich versuche, ein neues Array zu erstellen, das die Orte filtert, in denen nur Objekte enthalten sind, die nicht über die gleiche Stadteigenschaft verfügen (lat/lng-Duplikate sind in Ordnung). Gibt es eine eingebaute JS- oder Jquery-Funktion, um dies zu erreichen? 

24
theblueone

Ich würde wahrscheinlich ein Flags-Objekt während der Filterung verwenden, wie folgt:

_var flags = {};
var newPlaces = places.filter(function(entry) {
    if (flags[entry.city]) {
        return false;
    }
    flags[entry.city] = true;
    return true;
});
_

Hierfür wird Array#filter aus ECMAScript5 (ES5) verwendet. Dies ist eine der ES5-Ergänzungen, die angepasst werden können (suchen Sie nach "es5 shim" für mehrere Optionen).

Du kannst es ohne filter machen, natürlich ist es nur ein bisschen ausführlicher:

_var flags = {};
var newPlaces = [];
var index;
for (index = 0; index < places.length; ++index) {
    if (!flags[entry.city]) {
        flags[entry.city] = true;
        newPlaces.Push(entry);
    }
});
_

In beiden oben genannten Fällen wird davon ausgegangen, dass das erste Objekt mit einer bestimmten Stadt beibehalten und alle anderen Objekte verworfen werden sollen.


Hinweis: Wie der Benutzer 2736012 weiter unten ausführt, gilt mein Test if (flags[entry.city]) für Städte mit Namen, die zufällig mit den Eigenschaften von _Object.prototype_ übereinstimmen, z. B. toString. Sehr unwahrscheinlich in diesem Fall, aber es gibt vier Möglichkeiten, die Möglichkeit zu vermeiden:

  • (Meine übliche bevorzugte Lösung) Erstellen Sie das Objekt ohne Prototyp: var flags = Object.create(null);. Dies ist eine Funktion von ES5. Beachten Sie, dass dies nicht für veraltete Browser wie IE8 geändert werden kann (die Einzelargumentversion von _Object.create_ kann sein, außer , wenn der Wert dieses Arguments null ist. ).

  • Verwenden Sie für den Test hasOwnProperty, z. if (flags.hasOwnProperty(entry.city))

  • Fügen Sie ein Präfix hinzu, von dem Sie wissen, dass es für keine _Object.prototype_ -Eigenschaft existiert, z. B. xx:

    _var key = "xx" + entry.city;
    if (flags[key]) {
        // ...
    }
    flags[key] = true;
    _
  • Ab ES2015 können Sie stattdessen Set verwenden:

    _const flags = new Set();
    const newPlaces = places.filter(entry => {
        if (flags.has(entry.city)) {
            return false;
        }
        flags.add(entry.city);
        return true;
    });
    _
46
T.J. Crowder

Kürzeste, aber nicht die beste Leistung (siehe Update unten) Lösung für es6:

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

leistung: https://jsperf.com/compare-unique-array-by-immobilien

16
IgorL

Mein Vorschlag :

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);
        }
    }
}

in Benutzung :

places.uniqueCity();

oder

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');

Mit dem obigen können Sie das Array nach einem der Felder in den Objekten sortieren, selbst wenn diese für einige der Objekte nicht vorhanden sind.

oder

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

Ich habe die @ IgorL-Lösung etwas erweitert, aber den Prototyp erweitert und ihm eine Auswahlfunktion anstelle einer Eigenschaft gegeben, um ihn etwas flexibler zu machen:

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

Verwendungszweck:

// 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)

Definitiv NICHT der performanteste Weg, dies zu tun, aber solange der Selektor einfach ist und das Array nicht massiv ist, sollte es gut funktionieren.

In 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

Wie in den Kommentaren darauf hingewiesen, können Sie ein Objekt als Map verwenden, um Duplikate zu vermeiden. Dann können Sie die Eigenschaften des Objekts auflisten.

arbeitsgeige: 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

Sie können eine Map verwenden, damit die Einträge mit derselben Schlüsseleigenschaft (in Ihrem Fall 'Stadt') nur einmal angezeigt werden

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

Weitere Informationen zu Karten- und Array-Objekten hier

Grundlegendes Beispiel zu Codepen

0
Tamo Maes

Im einfachen Javascript Code werden doppelte Städte aus der places Array Liste entfernt

var places = [{ 'lat': 12.123, 'lng': 13.213, 'city': "New York"},
                { 'lat': 3.123, 'lng': 2.213, 'city': "New York"},
                { 'lat': 43.123, 'lng': 12.213, 'city': "London"}];
var unique = [];
var tempArr = [];
places.forEach((value, index) => {
    if (unique.indexOf(value.city) === -1) {
        unique.Push(value.city);
    } else {
        tempArr.Push(index);    
    }
});
tempArr.reverse();
tempArr.forEach(ele => {
    places.splice(ele, 1);
});
console.log(places);
0
Shridhar Sagari

Andere 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' }
])

Sie können es in Ihre Konsole einfügen, damit es funktioniert. Es sollte für das dargestellte Szenario und einige andere funktionieren.

0
rafaelbiten