Pregunta

Tengo un objeto como:

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

Quiero reducir los duplicados como:

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

¿Qué es una buena manera de hacer eso?

Algunas advertencias:

  • No siempre será solamente un pequeño número de pares. (En la actualidad existen 7; me podía imaginar que va hasta, por ejemplo, 20).
  • Los nombres de las propiedades iniciales siempre será solamente un único carácter, como en el ejemplo
  • Los valores potencialmente podría ejecutar a varios cientos de caracteres.
  • velocidad y de códigos de longitud son muy importantes, pero dado el pequeño número de filas, la claridad del código es probablemente aún más importante.
¿Fue útil?

Solución

Ir a través de cada propiedad del objeto y constructo otro objeto, donde las claves son los valores de la primera, y los valores son listas de claves (de la primera). Después de ir hacia atrás a través de ese segundo objeto y hacer que el resultado final.

Algo como esto:

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

Ahora bien, si los valores del objeto original no son cadenas, entonces las cosas se ponen más involucrados: sólo cadenas pueden ser claves de propiedad de un objeto Javascript. Usted podría mirar a su alrededor para una aplicación más general de hash, en ese caso. Si los objetos tienden a ser bastante pequeña (menos de 10 o menos unidades) se podría escribir el n 2 versión, en la que simplemente repetir las propiedades y luego iterar de nuevo para cada uno. Que probablemente sería una mala idea, sin embargo si los objetos pueden ser grandes y hay que realizar esta operación mucho.

Otros consejos

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

Usar como:

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

var ob2 = Reduce(obj);

Este es el más corto podría conseguir que:

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

Explicación:

  • Se recorre cada elemento en el objeto original, obj, y produce un nuevo objeto, newObj.
  • Para cada elemento de la original, se busca en la newObj media producida por el mismo valor. - El resultado es j, ya sea el nombre de la propiedad si lo encuentra, o una cadena vacía si no.
  • En cualquier caso, el nuevo objeto necesita una propiedad del mismo nombre que la propiedad actual en el objeto original, además de este valor de j.
  • También elimina la propiedad que se encuentra en newObj si había uno, para evitar duplicados están construyendo.

Es cierto que, j = "" ajuste dentro del bucle es ineficiente. Esto puede ser fácilmente reemplazado con un segundo conjunto de variables a "" inicialmente, y j sólo si se encuentra una coincidencia. Decidí ir por simplicidad sin embargo.

Sin una especie de mayor biblioteca de bucle acaba cada par (uso hasOwnProperty) y añadir / Anexar la clave para un histograma donde la clave histograma es el par de valores y los valores del histograma son las claves concatenados. Luego revertir la clave / valor del histograma.

Editar:. Si los valores iniciales no son cadenas (y no se asignan de forma reversible) a continuación, una biblioteca existente 'hash de identidad' todavía podría permitir que el enfoque anterior al trabajo

Como alternativa, puede asignar decir, [[k,v],...] y clasificar y luego usar un enfoque similar a un cubo especie (imagina que ya está clasificada) a los valores de combinación de "claves iguales" en el paso de salida.

Puede ir como esto (mientras que el código puede tener errores, el enfoque es el sonido - lo hará también el trabajo con objetos arbitrarios como los valores, siempre y cuando usted tiene una manera de comparar los valores):

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

Perdóname si estoy completamente fuera, pero me parece que la forma en que está la combinación de estos, tienes las llaves y los valores al revés. ¿Y esto?

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

debería ser bastante fácil de convertir:

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-compilado;. Que podría haber un par de errores)

Comenzar con un reducir que utiliza un diccionario para contar las etiquetas de una manera volteado. camino de buen calidad, ya que utiliza el construido en el diccionario de apoyo, sin los bucles, etc.

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

Devuelve un objeto con formato volteado:

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

A continuación, sólo darle la vuelta al formato:

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

Salida:

// {ac: "foo", be: "bar", d: "baz"}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top