Я собрал некоторый код, чтобы сгладить и разровнять сложные / вложенные объекты JSON. Это работает, но это немного медленно (вызывает предупреждение «длинный скрипт»).
Для сглаженных имен я хочу "." в качестве разделителя и [INDEX] для массивов.
Примеры:
un-flattened | flattened
---------------------------
{foo:{bar:false}} => {"foo.bar":false}
{a:[{b:["c","d"]}]} => {"a[0].b[0]":"c","a[0].b[1]":"d"}
[1,[2,[3,4],5],6] => {"[0]":1,"[1].[0]":2,"[1].[1].[0]":3,"[1].[1].[1]":4,"[1].[2]":5,"[2]":6}
Я создал бенчмарк, который ~ симулирует мой вариант использования http://jsfiddle.net/WSzec/
- Получить вложенный объект JSON
- Свести это
- Просмотрите его и, возможно, измените, пока он сплющен
- Разблокируйте его обратно в исходный вложенный формат для отправки
Я хотел бы более быстрый код: для пояснения, код, который завершает тест JSFiddle ( http://jsfiddle.net/WSzec/ ) значительно быстрее (было бы неплохо ~ 20% +) в IE 9+, FF 24+ и Chrome 29 +.
Вот соответствующий код JavaScript: Текущий самый быстрый: http://jsfiddle.net/WSzec/6/
JSON.unflatten = function(data) {
"use strict";
if (Object(data) !== data || Array.isArray(data))
return data;
var result = {}, cur, prop, idx, last, temp;
for(var p in data) {
cur = result, prop = "", last = 0;
do {
idx = p.indexOf(".", last);
temp = p.substring(last, idx !== -1 ? idx : undefined);
cur = cur[prop] || (cur[prop] = (!isNaN(parseInt(temp)) ? [] : {}));
prop = temp;
last = idx + 1;
} while(idx >= 0);
cur[prop] = data[p];
}
return result[""];
}
JSON.flatten = function(data) {
var result = {};
function recurse (cur, prop) {
if (Object(cur) !== cur) {
result[prop] = cur;
} else if (Array.isArray(cur)) {
for(var i=0, l=cur.length; i<l; i++)
recurse(cur[i], prop ? prop+"."+i : ""+i);
if (l == 0)
result[prop] = [];
} else {
var isEmpty = true;
for (var p in cur) {
isEmpty = false;
recurse(cur[p], prop ? prop+"."+p : p);
}
if (isEmpty)
result[prop] = {};
}
}
recurse(data, "");
return result;
}
РЕДАКТИРОВАТЬ 1 Изменено выше, чтобы реализация @Bergi, которая в настоящее время является самой быстрой. Кроме того, использование «.indexOf» вместо «regex.exec» примерно на 20% быстрее в FF, но на 20% медленнее в Chrome; поэтому я буду придерживаться регулярного выражения, поскольку это проще (вот моя попытка использовать indexOf для замены регулярного выражения http://jsfiddle.net/WSzec/2/ ).
РЕДАКТИРОВАТЬ 2 Опираясь на идею @Bergi, мне удалось создать более быструю версию без регулярных выражений (в 3 раза быстрее в FF и на 10% быстрее в Chrome). http://jsfiddle.net/WSzec/6/ В этой (текущей) реализации правила для имен ключей просты: ключи не могут начинаться с целого числа или содержать точку.
Пример:
- {"foo": {"bar": [0]}} => {"foo.bar.0": 0}
РЕДАКТИРОВАТЬ 3 Добавление подхода @AaditMShah для анализа встроенных путей (а не String.split) помогло улучшить производительность без обратной связи. Я очень доволен достигнутым общим улучшением производительности.
Последние версии jsfiddle и jsperf:
источник
[1].[1].[0]
выглядит неправильно для меня. Вы уверены, что это желаемый результат?Ответы:
Вот моя гораздо более короткая реализация:
flatten
не сильно изменился (и я не уверен, действительно ли вам нужны этиisEmpty
случаи):Вместе они запускают ваш тест примерно в половине случаев (Opera 12.16: ~ 900 мс вместо ~ 1900 мс, Chrome 29: ~ 800 мс вместо ~ 1600 мс).
Примечание. Это и большинство других решений, на которые даны ответы, фокусируются на скорости и подвержены загрязнению прототипа и не должны использоваться на ненадежных объектах.
источник
result === data
не сработает, они никогда не идентичны.Я написал две функции
flatten
иunflatten
объект JSON.Свести объект JSON :
Производительность :
Разблокируйте объект JSON :
Производительность :
Выровнять и развернуть объект JSON :
В целом, мое решение работает так же хорошо или даже лучше, чем текущее решение.
Производительность :
Выходной формат :
Плоский объект использует точечную нотацию для свойств объекта и скобочную нотацию для индексов массива:
{foo:{bar:false}} => {"foo.bar":false}
{a:[{b:["c","d"]}]} => {"a[0].b[0]":"c","a[0].b[1]":"d"}
[1,[2,[3,4],5],6] => {"[0]":1,"[1][0]":2,"[1][1][0]":3,"[1][1][1]":4,"[1][2]":5,"[2]":6}
На мой взгляд, этот формат лучше, чем только использование точечной нотации:
{foo:{bar:false}} => {"foo.bar":false}
{a:[{b:["c","d"]}]} => {"a.0.b.0":"c","a.0.b.1":"d"}
[1,[2,[3,4],5],6] => {"0":1,"1.0":2,"1.1.0":3,"1.1.1":4,"1.2":5,"2":6}
Преимущества :
Недостатки :
Текущая демонстрация JSFiddle выдает следующие значения в качестве вывода:
Моя обновленная демоверсия JSFiddle выдала следующие значения:
Я не совсем уверен, что это значит, поэтому я буду придерживаться результатов jsPerf. В конце концов, jsPerf - это утилита для измерения производительности. JSFiddle нет.
источник
unflatten({"foo.__proto__.bar": 42})
3 с половиной года спустя ...
Для моего собственного проекта я хотел сгладить объекты JSON в точечной нотации mongoDB и предложил простое решение:
Особенности и / или предостережения
{a: () => {}}
вы можете не получить то, что хотели!{a: {}, b: []}
сглаживается{}
.источник
{"x": "abc\"{x}\"yz"}
становится{ "x": "abc"{,"x",}"yz"}
недействительным.Версия ES6:
Пример:
источник
Date
, есть идеи, как заставить это сделать? Например, сflatten({a: {b: new Date()}});
Вот еще один подход, который работает медленнее (около 1000 мс), чем приведенный выше ответ, но имеет интересную идею :-)
Вместо итерации по каждой цепочке свойств, он просто выбирает последнее свойство и использует справочную таблицу для остальных, чтобы сохранить промежуточные результаты. Эта справочная таблица будет повторяться до тех пор, пока не останется цепочек свойств, а все значения будут находиться в некокатированных свойствах.
В настоящее время он использует
data
входной параметр для таблицы и накладывает на него множество свойств - также возможна неразрушающая версия. Может быть, умноеlastIndexOf
использование работает лучше, чем регулярное выражение (зависит от движка регулярных выражений).Смотрите это в действии здесь .
источник
unflatten
неправильно выравнивает объект. Например, рассмотрим массив[1,[2,[3,4],5],6]
. Вашаflatten
функция выравнивает этот объект до{"[0]":1,"[1][0]":2,"[1][1][0]":3,"[1][1][1]":4,"[1][2]":5,"[2]":6}
. Вашаunflatten
функция, однако, неправильно раскрывает сплющенный объект до[1,[null,[3,4]],6]
. Причина этого заключается в том,delete data[p]
что оператор преждевременно удаляет промежуточное значение[2,null,5]
перед[3,4]
его добавлением к нему. Используйте стек, чтобы решить это. :-)Вы можете использовать https://github.com/hughsk/flat
Пример из документа
источник
Этот код рекурсивно выравнивает объекты JSON.
Я включил свой механизм синхронизации в код, и он дает мне 1 мс, но я не уверен, что это самый точный.
Вывод:
источник
typeof some === 'object'
быстрее, чемsome instanceof Object
первая проверка в O1, а вторая в On, где n - длина цепочки наследования (Object всегда будет последней).Я добавил +/- 10-15% эффективности к выбранному ответу путем незначительного рефакторинга кода и перемещения рекурсивной функции за пределы пространства имен функции.
Смотри мой вопрос: переоцениваются ли функции пространства имен при каждом вызове? почему это замедляет вложенные функции.
Смотрите бенчмарк .
источник
Вот мой. Он запускается в <2ms в скрипте Google Apps для значительного объекта. Он использует тире вместо точек для разделителей, и он не обрабатывает массивы, как в вопросе Аскера, но это то, что я хотел для моего использования.
Пример:
Пример вывода:
источник
Используйте эту библиотеку:
Использование (с https://www.npmjs.com/package/flat ):
Свести:
Un-выравниваться:
источник
Я хотел бы добавить новую версию flatten case (это то, что мне было нужно :)), которая, согласно моим исследованиям с вышеупомянутым jsFiddler, немного быстрее, чем текущая выбранная. Более того, я лично вижу этот фрагмент немного более читабельным, что, конечно, важно для проектов с несколькими разработчиками.
источник
Вот некоторый код, который я написал, чтобы сгладить объект, с которым я работал. Он создает новый класс, который берет каждое вложенное поле и переносит его на первый слой. Вы можете изменить его так, чтобы он был открыт, запомнив оригинальное расположение клавиш. Также предполагается, что ключи уникальны даже для вложенных объектов. Надеюсь, поможет.
Как пример, он преобразует
в
источник