Frage

Ich habe ein Objekt bekam wie:

{
    a : 'foo',
    b : 'bar',
    c : 'foo',
    d : 'baz',
    e : 'bar'
}

Ich mag die Duplikate reduzieren wie:

{
    ac : 'foo',
    be : 'bar',
    d : 'baz'
}

Was ist ein guter Weg, das zu tun?

Ein paar Einschränkungen:

  • Es wird immer nur eine kleine Anzahl von Paaren sein. (Zur Zeit gibt es 7; ich konnte es sich vorstellen, gehen bis zu, sagen wir, 20).
  • Die ersten Eigenschaftsnamen wird immer nur ein einzelnes Zeichen sein, wie im Beispiel
  • Die Werte möglicherweise auf mehrere hundert Zeichen laufen konnte.
  • sowohl Geschwindigkeit und Code-Länge von großer Bedeutung ist, aber die kleine Anzahl von Zeilen, Code Klarheit gegeben ist wahrscheinlich immer noch am wichtigsten ist.
War es hilfreich?

Lösung

Gehen Sie durch jede Eigenschaft des Objekts und Konstrukt andere Objekt, wo die Schlüssel die Werte des ersten sind, und die Werte sind Listen von Schlüsseln (von der ersten). Dann gehen Sie zurück durch dieses zweite Objekt und das Endergebnis machen.

So etwas wie folgt aus:

function noDupes(obj) {
  var o2 = {};
  for (var k in obj) {
    if (obj.hasOwnProperty(k)) {
      var list = o2[obj[k]] || [];
      list.push(k);
      o2[obj[k]] = list;
    }
  }
  var rv = {};
  for (k in o2) {
    if (o2.hasOwnProperty(k))
      rv[o2[k].join('')] = k;
  }
  return rv;
}

Nun, wenn die Werte des ursprünglichen Objekts keine Strings sind, dann werden die Dinge mehr beteiligt: ??nur Strings können Eigenschaftsschlüssel in einem Javascript-Objekt sein. Sie könnten für eine allgemeinere Hash-Implementierung schauen Sie sich um, in diesem Fall. Wenn Ihre Objekte sind in der Regel ziemlich klein (weniger als 10 oder so Eigenschaften) können Sie die n 2 Version schreiben, in dem Sie einfach Iterierte über die Eigenschaften und dann wieder für Iterierte jeden. Das wäre wohl aber eine schlechte Idee, wenn Ihre Objekte groß sein könnten und Sie haben diese Operation auszuführen viel.

Andere Tipps

var Reduce = function(obj)
{
  var temp = {};
  var val = "";

  for (var prop in obj)
  {
    val = obj[prop];
    if (temp[val])
      temp[val] = temp[val] + prop.toString();
    else
      temp[val] = prop.toString();
  }

  var temp2 = {};

  for (var prop in temp)
  {
    val = temp[prop];
    temp2[val] = prop.toString();
  }

  return temp2;
};

Anwendung:

var obj = {
  a :"foo",
  b : "bar",
  c : "foo",
  d : "bar", 
  e : "bar"
};

var ob2 = Reduce(obj);

Dies ist die kürzeste, ich könnte es bekommen:

var obj, newObj = {}; // obj is your original
for (var i in obj) {
    if (!obj.hasOwnProperty(i)) continue;
    for (var j in newObj) {
        if (newObj.hasOwnProperty(j) && newObj[j] === obj[i]) break;
        j = "";
    }
    newObj[i + j] = obj[i];
    j && delete newObj[j];
}

Erklärung:

  • Es Schleifen durch jedes Element in dem ursprünglichen Objekt, obj und erzeugt ein neues Objekt, newObj.
  • Für jedes Element in der ursprünglichen, sucht es die Halb erzeugt newObj für den gleichen Wert. - Das Ergebnis ist j, entweder der Name der Eigenschaft, wenn gefunden wird, oder eine leere Zeichenfolge, wenn nicht.
  • In jedem Fall wird das neue Objekt braucht eine Eigenschaft mit dem gleichen Namen wie das aktuelle Objekt in das ursprüngliche Objekt, zuzüglich diesen Wert von j.
  • Es löscht auch das gefundene Objekt in newObj wenn es eine ist, um Duplikate zu verhindern gebaut.

Zwar Einstellung j = "" innerhalb der Schleife ist ineffizient. Dies kann leicht mit einem zweiten variablen Satz ersetzt wird zunächst auf "" und j nur, wenn eine Übereinstimmung gefunden wird. Ich entschied, obwohl der Einfachheit halber zu gehen.

Ohne eine höhere Art Bibliothek nur Schleife jedes Paar (Verwendung hasOwnProperty) und Add / append der Schlüssel zu einem Histogramm, wo das Histogramm Schlüssel ist das Paar Wert ist, und die Histogrammwerte werden die verketteten Schlüssel. Dann kehrt die Schlüssel / Werte des Histogramms.

Edit:. Wenn die Anfangswerte sind keine Strings (und Karte nicht reversibel), dann eine vorhandene Identität Hash 'Bibliothek könnte immer noch den oben beschriebenen Ansatz Arbeit ermöglichen

Alternativ können Sie sagen, Karte, [[k,v],...] und sortieren und dann einen Ansatz verwenden ähnlich einem Bucketsort (man stelle es bereits sortierte) zu fusionieren Werte von „equal Tasten“ in der Ausgabe weiter.

Es kann weitergehen (während des Code Fehler haben kann, ist der Ansatz, Ton - es wird auch die Arbeit mit beliebigen Objekten als Wert so lange, wie Sie eine Möglichkeit haben, die Werte zu vergleichen):

var _f = []
for (var k in map) {
  if (map.hasOwnProperty(k)) {
    _f.push({k: k, v: map[k]})
  }
}
// you could also sort on name (a.k), if it's important
// this makes it more versatile and deterministic in output
// ordering than the histogram method above
var f = _f.sort(function (a, b) { return a.v < b.v ? 1 : a.v > b.v ? -1 : 0 })

var res = {}
var prev
var name = ""
// after the sort all {k:,v:} objects with the same values will be grouped
// together so we only need to detect the change to the next value
// and everything prior to that gets the merged key
for (var i = 0; i < f.length; i++) {
  var p = f[i]
  if (prev != p.v && name) {
    res[name] = prev
    name = ""
  } else {
    name = name + p.k
  }
  prev = p.v
}
if (name) { // don't forget last set of values
  res[name] = prev
}

// have res

Verzeih mir, wenn ich vollständig aus bin, aber es scheint mir, dass die Art und Weise Sie diese sind kombiniert, haben Sie die Schlüssel und die Werte falsch herum. Was ist das?

{
    'foo': ['a', 'c'],
    'bar': ['b', 'e'],
    'baz': ['d']
}

Sollte leicht genug, um zu konvertieren sein:

flippedObj = {};
for (var letter in obj) {
    if (obj.hasOwnProperty(letter)) {
        var letters = flippedObj[obj[letter]];
        if (letters === undefined) {
            letters = [];
            flippedObj[obj[letter]] = letters;
        }

        letters.push(letter);
    }
}

(Brain-kompiliert,. Es könnte ein paar Fehler sein)

Starten Sie mit einem reduzieren, dass ein Wörterbuch Anwendungen, die Tags in einer Art und Weise gekippt zu zählen. Sehr performante Art und Weise, da die in Wörterbuchunterstützung gebaut es verwendet, nicht für Schleifen etc.

var flipped = Object.keys(input).reduce(function(a,b){
  var tag = input[b];
  a[tag] = (a[tag] || '') + b;
  return a;
}, {});

Gibt ein Objekt mit blätterte Format:

// {foo: "ac", bar: "be", baz: "d"}

Dann spiegelt nur das Format:

Object.keys(flipped).reduce(function(a,b){
  a[flipped[b]]=b;
  return a;
}, {});

Ausgabe:

// {ac: "foo", be: "bar", d: "baz"}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top