Ваниль JS (FUN ONE): лучший способ получить доступ к глубоко скрытому узлу JSON из строки "map" - PullRequest
0 голосов
/ 10 марта 2020

Lead-Up

Я только что наткнулся (гораздо менее надуманная версия) на сценарий, который я изложил ниже. Есть десятки способов справиться с этим - от рекурсивных функций до рендеринга в DOM и использования treewalker - и даже не удивительно, что есть какой-то неясный фрагмент JS эзотерики, который обрабатывает эту точную информацию проблема, о которой я просто не знаю.

Дело в том, что это больше лапша, чем вы думаете . Читать дальше. Обещаю, это вас зацепит.

Видите, Я был JS разработчиком в течение 25 лет . Все чаще часть моих обязанностей все чаще включает в себя интервьюирование потенциальных разработчиков интерфейса . Мне достаточно нравится эта проблема, чтобы представить ее в моем репертуаре в качестве одного из моих вопросов о том, как кандидат думает. Я был бы очень признателен за любой вклад, и я хотел бы посмотреть, как люди будут решать это в дикой природе.

Структура данных

Оооочень ... допустим, у меня есть массивный (но действительный ) JSON объект.

Давайте назовем это n слоями (скажем, дамп реляционной базы данных или тому подобное. Вариант использования здесь не имеет значения; это интересующий меня tacti c), состоящий из различных типы данных (например, массив, объект, строка, число, логическое значение и т. д.).

Образец объекта

    const singledOut = {
    planets: [
        // Author's note: to distinguish these ellipses from the spread operator, I'll italicize 'em :)
        ...
        {"Venus": {...}}, 
        {"Earth": {
            ...
            "composition": [...],
            "continents":  [
                ...
                "Europe":     {...},
                "NorthAmerica"   {
                    ...
                    "climates":    [...],
                    "countries":   [
                        "Canada":        {...}   // ...and so on; you get the idea. Once we've drilled
                        "Mexico":        {...}   // far enough down to get good and granular, assume we'd
                        "UnitedStates":  {...}   // start seeing simple data types (string, numbers, etc)
                                ],
                    "currencies":  [...],            
                    ...
                            },
                "SouthAmerica"   {...},
                ...
            ],
            "craters":     [...]
            ...
        {"Mars":  {...}},
        ...
    ]
}

Для целей данного упражнения мы можем предположить, что у нас - уже загружен в память - доступ к рассматриваемому объекту JSON (то есть, какой-то крайне плохо спроектированный API вырвал нас обратно в этот большой объект wankin ', от которого нам нужен один тривиальный бит данных), но мы ЗНАЙТЕ путь к нему!


Локатор

Теперь давайте предположим, что у меня есть динамически генерируемый путь с разделителями в виде строки для в нем содержится «адрес» некоторого узла. Допустим, мы используем тильды (~) в качестве разделителя, и давайте также объявим, что источник данных не содержит этих символов (или они закодированы), чтобы исключить опасения по поводу загрязнения данных / необходимости справляться с escape-символами.

Пример «пути» к некоторым подробным сведениям о глубоко закопанных данных

"planets~Earth~continents~NorthAmerica~countries~UnitedStates~states~California~ ... ~Disneyland~fauna~giant mice"

Предположим, что нам нужны данные о количестве гигантских мышей, населяющих Диснейленд в Анахайме, Калифорния, США, Северная Америка, Земля


Бит Паззла

Так что на самом деле здесь похоронено четыре вопроса .

  1. Вам не нужно отвечать на них все, или, если вы решите,
  2. Один и тот же ответ не обязательно должен применяться ко всем 4 сценариям ios (хотя, если вы может думать об одном я буду впечатлен как ад).

СКЭНАР IOS:

  • СЦЕНАРИЙ ОДИН: Выложено в точности как указано выше. У вас есть ваш объект, у вас есть ваш путь строки. Как нам применить строку к JSON, чтобы получить нужный самородок?

  • СЦЕНАРИЙ ДВА: Также как и выше, но на этот раз мы имеем только ЗНАЧИТЕЛЬНЫЕ части КВП: `Земля ~ Северная Америка ~ Соединенные Штаты ~ Калифорния ~ Оранжевый ~ Анахайм ~ TouristTraps ~ Диснейленд ~ РОУС

  • СКЭНАР IOS ТРИ И ЧЕТЫРЕ: То же, что ОДИН и ДВА ... но мы вынуждены начать с этого массивного хонкинского объекта как STRING (JSON.stringify 'd).

цель во всех 4 состоит в том, чтобы извлечь титбит данных за наименьшее количество шагов / операций с наименьшим объемом памяти, которым мы можем управлять (кроме того, что уже было использовано). Короче говоря, рекурсивная функция, которая использует JSON.Parse(JSON.stringify()) chicanery (которая, хотя она и будет работать полностью, не может быть наилучшим вызовом памяти с уровнями рекурсии n , понятно?).

Мы можем предположить , что данные, которые мы ищем, живут в своем собственном уникальном узле (например, они не расположены внутри какого-то нумерованного списка, похороненного внутри указанного узла; ничего подобного "1 собаки, 4 утки, 2 мыши, 75 золотых верблюдов, 53 фиолетовых павлина, 95 белых персидских обезьян, 1 тигр ... и Гуфи "), но существует возможность, что запрашиваемые данные каким-то образом предварительно или суффиксированы (" Известно, что 2 "," 2 гигантские мыши "или" Диснейленд приютит 2 больших грызунов ")

Хитрый бит даже заставляет операцию превращения строковой версии "a~sample~path~like~this" в KEY-версию ["a"]["sample"]["path"]["like"]["this"] разочаровывающе неэффективно почти во всех решениях, которые я придумать.

Итак, я понял, какого черта: Лучшие разработчики ON planet~Earth живут на этом сайте. Я спрошу их. Все, что сказал, любая форма JS voodoo - это честная игра, но если есть какая-то странная библиотека, которая делает это специально, не забывайте учитывать ее вес и размеры в ваших ответах. Включая все, скажем Ext JS, только для этой одной проблемы, скорее всего, нет отличное решение как такие вещи go.

Я не могу дождаться, чтобы увидеть, что это получится! Кроме того, вы никогда не знаете: может быть, вы будете моим следующим собеседованием!

1 Ответ

0 голосов
/ 10 марта 2020

Я не претендую на звание эксперта javascript, не говоря уже о "одном из лучших разработчиков на планете ~ Земле", но ответ на ваш вопрос о преобразовании "a~sample~path~like~this" в KEY-версию ["a"]["sample"]["path"]["like"]["this"] кажется достаточно просто:

"a~sample~path~like~this".split('~').reduce((a,v)=>a[v], bigObject)

Это не близко к решению вашего исходного вопроса, когда недостаточно просто индексировать по ключу. Тем не менее, он может быть использован в качестве основы, поскольку все, что нужно, это изменить функцию сокращения, чтобы она была немного более общей. Но мне трудно ответить, потому что я не понимаю, что вы намереваетесь, например,

"countries": [
    "Canada":  {...}
    "Mexico":  {...}
    "UnitedStates":  {...}
]

, что далеко не является действительным JSON (или Javascript) объектом, поскольку массивы не могут иметь явных ключей (а элементы массивов необходимо разделять запятыми). Если вы имели в виду это:

"countries": [
    { "Canada":  {...} },
    { "Mexico":  {...} },
    { "UnitedStates":  {...} },
]

(что в лучшем случае является представлением эксцентри c), то вы можете использовать], "~ образец ~ путь ~ как ~ это" .split (' ~ ') .reduce ((a, v) => экземпляр массива? a.find (k => k [v]) [v]: a [v], bigObject)

В качестве альтернативы для этого представление (которое я видел в дикой природе):

"countries": [
    { "label": "Canada", ...},
    { "label": "Mexico", ...},
    { "label": "UnitedStates", ...},
]

вы можете использовать что-то вроде:

"a~sample~path~like~this"
   .split('~')
   .reduce((a,v)=>a instanceof Array ? a.find(k=>k.label==v) : a[v],
           bigObject)

Еще более сложная функция сокращения может включать в себя поиск в глубину поиска через агрегирует, чтобы увидеть, есть ли вложенное значение с желаемым ключом или значением, или чем-то еще.

Для случая, когда объект JSON все еще является строкой, лучшим вариантом IMHO будет использование потоковой передачи JSON парсер (Google нашел меня clar inet, что выглядит правдоподобно). Точные детали реализации будут зависеть от особенностей синтаксического анализатора JSON, но основная идея c заключается в том, чтобы поместить последовательность клавиш во что-то, что может быть проиндексировано (возможно, с использованием split, как указано выше для создания массива), и затем поддерживать индекс в этой последовательности, пока анализатор исследует объект. Думаю, это не так просто, как кажется, но и не слишком сложно. Простое решение - сохранить стек ключевых показателей. Когда анализатор указывает, что он собирается исследовать подэлемент, текущий индекс помещается в стек; когда синтаксический анализатор указывает, что он завершил исследование подэлемента, стек выталкивается. Когда синтаксический анализатор указывает, что ключ был обнаружен, и он соответствует текущей цели, текущий индекс увеличивается. Этот случай также необходимо проверить, когда стек вытолкнут; если значение, извлеченное из стека, является длиной последовательности клавиш, значение, только что законченное, является желаемым результатом поиска.

...