Menge von Objekten in Javascript

Lesezeit: 6 Minuten

Ich möchte eine Reihe von Objekten in Javascript haben. Das heißt, eine Datenstruktur, die nur eindeutige Objekte enthält.

Normalerweise wird die Verwendung von Eigenschaften empfohlen, z myset["key"] = true. Ich brauche jedoch die Schlüssel, um Objekte zu sein. Ich habe gelesen, dass Javascript Eigenschaftsnamen in Zeichenfolgen umwandelt, also kann ich es wohl nicht verwenden myset[myobject] = true.

Ich könnte ein Array verwenden, aber ich brauche etwas Besseres als O (n) Leistung zum Hinzufügen, Suchen und Entfernen von Elementen.

Es muss in der Lage sein, Objekte nur durch Referenz zu unterscheiden, also gegeben:

var a = {};
var b = {};

dann beides a und b sollten hinzugefügt werden können, da es sich um separate Objekte handelt.

Im Grunde bin ich nach so etwas wie C++ std::set, die Javascript-Objekte speichern kann. Irgendwelche Ideen?

  • mögliches Duplikat der JavaScript-Implementierung einer Satzdatenstruktur

    – Ciro Santilli OurBigBook.com

    15. Juni 2014 um 15:45 Uhr

Benutzeravatar von Ry-
Ry-

ES6 bietet eine native Set:

let s = new Set();
let a = {};
let b = {};

s.add(a);

console.log(s.has(a));  // true
console.log(s.has(b));  // false

  • new Set([{one: "one"}, {one: "one"}]).size ist 2. Sollte es nicht 1 sein?

    – ndtreviv

    11. Dezember 2018 um 12:35 Uhr

  • @ndtreviv: Nein, sie sind nicht dasselbe Objekt. {one: "one"} !== {one: "one"}

    – Ry-

    11. Dezember 2018 um 15:30 Uhr

  • Sie haben Recht. Am Ende habe ich Lodashs _.uniqWith und _.isEqual verwendet, um eindeutige Objekte zu erhalten.

    – ndtreviv

    11. Dezember 2018 um 20:34 Uhr

  • Danke @ndtreviv! ich benutzte uniqueObjects = _.uniqWith(objects, _.isEqual)

    – Jörick

    3. Januar 2020 um 12:24 Uhr

Hier ist ein toller Vorschlag … tippe auf das Ergebnis JSON.stringify(object)

  • Daran denke ich immer wieder, aber ich möchte die Dinge wirklich nicht so machen :/

    – Charly L

    22. Juli 2017 um 18:05 Uhr

  • TypeError: zyklischer Objektwert

    – Schrittmacher

    14. Juni 2020 um 17:56 Uhr

Es ist nicht für alle Objekte möglich, aber wenn Ihr Objekt eine hat .toString() Methode implementiert, es ist:

var x = {toString: function(){ return 'foo'; }};
var y = {toString: function(){ return 'bar'; }};
var obj = {};
obj[x] = 'X';
obj[y] = 'Y';
console.log(obj);
// { foo: 'X', bar: 'Y' }

Wenn Sie dies einfacher machen möchten, machen Sie es zu einer Klasse:

function myObj(name){
   this.name = name;
}
myObj.prototype.toString = function(){ return this.name; }

var obj = {};
obj[new myObj('foo')] = 'X';
obj[new myObj('bar')] = 'Y';

  • Alle Objekte haben eine toString Methode geerbt von Objekt.Prototyp. Wenn Sie das Objekt einem Eigenschaftsnamen zuweisen, wird es aufgerufen toString -Methode sowieso, so dass Sie dies nicht explizit tun müssen. Sie können nicht garantieren, dass ein Objekt toString wird für alle Objekte eindeutig sein, daher ist der Ansatz von Sophistifunk besser (dh Objekte in einem Array speichern und einen Wrapper mit Methoden zum Hinzufügen, Abrufen und Entfernen von Mitgliedern bereitstellen).

    – RobG

    14. April 2011 um 1:43 Uhr


  • @RobG – Du verfehlst den Punkt. Das toString() Methoden, die ich hinzugefügt habe, waren, damit Sie einen eindeutigen Hash des aktuellen Objekts zurückgeben können. In diesem Fall kehre ich einfach zurück 'foo' und 'bar'aber Sie könnten leicht alles andere hashen, das das Objekt identifiziert (daher die prototype Beispiel). Was Ihre erste Aussage betrifft, nein… Zuordnung toString() als Eigenschaft wird diese Funktion aufrufen, NICHT diejenige, von der sie erbt Object.prototype

    Benutzer578895

    14. April 2011 um 1:46 Uhr


  • Meinetwegen, var guid=0; myObj.prototype.toString = function(){ return (this.guid || (this.guid=guid++)); } würde funktionieren.

    Benutzer578895

    14. April 2011 um 1:50 Uhr


  • @cwolves – alle gespeicherten Objekte müssen eindeutige Namen haben, also besser automatisieren und privat halten.

    – RobG

    14. April 2011 um 2:10 Uhr

  • @RobG – Wenn alle Objekte vom gleichen Typ sind, ist es besser, dies so zu tun (siehe meinen letzten Guid-Kommentar, wenn Sie möchten), da es sich im Gegensatz zu Array.indexOf um O (1) -Lookups handelt

    Benutzer578895

    14. April 2011 um 2:14 Uhr

Ich beantworte meine eigene Frage, aber ich habe eine alternative Lösung gefunden, die ich interessant fand und der Meinung war, dass es nützlich wäre, sie zu teilen.

Die Antwort von Cwolves brachte mich auf eine Idee. Bereitstellung eines Objekts toString() -Methode die Instanz eindeutig identifiziert, können Eigenschaften eines Objekts verwendet werden, um eine Menge von Objekten zu speichern. Im Wesentlichen zum Speichern von Objekten xkönnen Sie verwenden items[x.toString()] = x;. Beachten Sie, dass der Wert das Objekt selbst ist, sodass die Menge der Objekte extrahiert werden kann, indem Sie überhaupt suchen item‘s Eigenschaften und Ausgeben aller Werte in ein Array.

Hier ist die Klasse, die ich anrufe ObjectSet, vollständig. Es erfordert, dass Objekte durch ihre eindeutig identifiziert werden toString() Methode, die für meine Zwecke in Ordnung ist. add, remove und contains sollten alle in besserer Zeit als O(n) laufen – was auch immer die Effizienz des Zugriffs auf Eigenschaften von Javascript ist, die hoffentlich entweder O(1) oder O(n log n) ist.

// Set of objects.  Requires a .toString() overload to distinguish objects.
var ObjectSet = function ()
{
    this.items = {};
    this.item_count = 0;
};

ObjectSet.prototype.contains = function (x)
{
    return this.items.hasOwnProperty(x.toString());
};

ObjectSet.prototype.add = function (x)
{
    if (!this.contains(x))
    {
        this.items[x.toString()] = x;
        this.item_count++;
    }

    return this;
};

ObjectSet.prototype.remove = function (x)
{
    if (this.contains(x))
    {
        delete this.items[x.toString()];
        this.item_count--;
    }

    return this;
};

ObjectSet.prototype.clear = function ()
{
    this.items = {};
    this.item_count = 0;

    return this;
};

ObjectSet.prototype.isEmpty = function ()
{
    return this.item_count === 0;
};

ObjectSet.prototype.count = function ()
{
    return this.item_count;
};

ObjectSet.prototype.values = function ()
{
    var i, ret = [];

    for (i in this.items)
    {
        if (this.items.hasOwnProperty(i))
            ret.push(this.items[i]);
    }

    return ret;
};

Benutzeravatar von Vivin Paliath
Vivin Paliath

Für das, was Sie versuchen (Objektsätze), gibt es keine native Javascript-Implementierung. Diese müssten Sie selbst umsetzen. Eine Möglichkeit wäre, eine Hash-Funktion für Ihre Objekte zu implementieren. Der unterstützende Datentyp des Satzes wäre ein assoziatives Array, wobei der Schlüssel des Arrays der Wert ist, den Sie durch Aufrufen der Hash-Funktion des Objekts erhalten, und der Wert des Arrays das Objekt selbst ist.

Natürlich geht dies nicht auf das von Ihnen hervorgehobene Problem ein, also müssen Sie auch die Gleichheit berücksichtigen (implementieren Sie vielleicht eine Gleichheitsfunktion)?

Anstatt die Hash-Funktion zu einer Eigenschaft des Objekts selbst zu machen, können Sie eine eigenständige Hash-Funktion haben, die ein Objekt als Eingabe aufnimmt und einen Hash-Wert generiert (vermutlich durch Iteration über seine Eigenschaften).

Mit dieser Methode sollten Sie in der Lage sein, zu bekommen O(1) zum Einfügen, Suchen und Entfernen (ohne die Reihenfolge der Hash-Funktion zu zählen, die nicht schlechter sein sollte als O(n)insbesondere wenn Sie über seine Eigenschaften iterieren, um Ihren Hash-Wert zu erstellen).

ECMAScript6 Set sollte sich so verhalten:

Arbeitsbeispiel auf Firefox 32 (aber nicht in Chromium 37 implementiert):

if (Set) {
  var s = new Set()
  var a = {}
  var b = {}
  var c = {}
  s.add(a)
  s.add(b)
  s.add(b)
  assert(s.size === 2)
  assert(s.has(a))
  assert(s.has(b))
  assert(!s.has(c))
}

Dies ist nicht verwunderlich, da {} != {}: Gleichheit vergleicht standardmäßig Objektadressen.

Ein Modul, das es für Browser ohne Unterstützung implementiert: https://github.com/medikoo/es6-set

Benutzeravatar von ENcy
ENcy

Ich habe Map benutzt, meinen Fall gelöst

const objectsMap = new Map();
const placesName = [
  { place: "here", name: "stuff" },
  { place: "there", name: "morestuff" },
  { place: "there", name: "morestuff" },
];
placesName.forEach((object) => {
  objectsMap.set(object.place, object);
});
console.log(objectsMap);

  • Perfekte Lösung. Danke

    – Yehya

    20. September um 13:16 Uhr

1430770cookie-checkMenge von Objekten in Javascript

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy