Уменьшите дубликат в объекте JavaScript
-
30-09-2019 - |
Вопрос
У меня есть объект, как:
{
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"}