Вопрос

У меня есть объект, как:

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

Я хочу уменьшить дубликаты, такие как:

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

Какой хороший способ сделать это?

Несколько предостережений:

  • Там только когда-либо будет небольшое количество пар. (В настоящее время есть 7; я мог себе представить, что это подходит, скажем, 20.)
  • Начальные имена свойств будут только один символ, как в примере
  • Значения могут потенциально работать до нескольких сотен символов.
  • Как скорость, так и длина кода очень важны, но учитывая небольшое количество строк, ясность кода, вероятно, все еще является наиболее важным.
Это было полезно?

Решение

Пройти через каждую свойство объекта и построить еще один Объект, где ключи являются значениями первых, и значения являются списки ключей (с первого). Затем вы вернитесь через этот второй объект и сделайте окончательный результат.

Что-то вроде этого:

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

Теперь, если значения исходного объекта не являются строками, то все больше участвуют: только строки могут быть ключами свойства в объекте JavaScript. Вы могли бы осмотреться за более общему хэш-реализацией в этом случае. Если ваши объекты имеют тенденцию быть довольно маленькими (менее 10 или около того свойств), вы можете записать N2 Версия, где вы просто повторяете свойства, а затем повторяете еще раз для каждого. Это, вероятно, будет плохой идеей, однако, если ваши объекты могут быть большими, и вы должны много работать.

Другие советы

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

Использовать как:

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

var ob2 = Reduce(obj);

Это самый короткий, который я мог бы получить:

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

Объяснение:

  • Он петли через каждый элемент в исходном объекте, obj, и производит новый объект, newObj.
  • Для каждого элемента в оригинале он ищет полугодие newObj за то же значение. - результат j, либо имя свойства, если она найдена или пустая строка, если нет.
  • В любом случае новый объект нуждается в свойство того же имени, что и текущее свойство в исходном объекте, плюс это значение j.
  • Это также удаляет найденное недвижимость в newObj Если бы было один, чтобы предотвратить построенные дубликаты.

По общему признанию, настройка j = "" В рамках петли неэффективно. Это может быть легко заменено на вторую переменную, установленную на "" Изначально и j только если совпадение найдено. Я решил пойти на простоту, хотя.

Без библиотеки более высокой доброй добыты просто петля каждой пары (используйте hasOwnProperty) и добавьте / добавьте ключ к гистограмме, в котором ключ гистограммы - это паруе значение, а значения гистограммы являются объединенные клавиши. Затем поменяйте ключ / значения гистограммы.

Редактировать: Если начальные значения не являются строками (и не отображаются на карте обратимо), то существующая библиотека HASH HASH HASHH может еще включить вышеуказанный подход к работе.

Альтернативно, вы можете сказать, чтобы сказать, [[k,v],...] и сортировать, а затем использовать подход, аналогичный сортировка ведра (Представьте себе, что это уже отсортировано), чтобы объединить значения «равных клавиш» в выходной проход.

Это может пойти так (пока код может иметь ошибки, подход звучит - он также будет работать с произвольными объектами в качестве значений до тех пор, пока у вас есть способ сравнить значения):

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

Прости меня, если я полностью выйду, но мне кажется, что то, как вы объединяете их, у вас есть ключи и значения неправильно. Что насчет этого?

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

Должно быть достаточно легко, чтобы преобразовать:

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

(Компиляция мозга; может быть паре ошибок.)

Начните с уменьшения, которые используют словарь для подсчета тегов в перевернутый путь. Очень исполнительный способ, поскольку он использует встроенную поддержку словаря, нет для петлей и т. Д.

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

Возвращает объект с переброшенным форматом:

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

Тогда просто переверните формат:

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

Выход:

// {ac: "foo", be: "bar", d: "baz"}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top