Работа с json массивами.

Sorcus

Sorcus. A New Beginning.
Регистрация
10 Июл 2011
Сообщения
513
Реакции
1.002
Собственно есть json массив, в котором ключи могут быть, а могут и не быть.
Код:
value = array['item']['value']
array['item'] может быть пустым, либо содержать ['value']
Если array['item'] пустой, то код выше валится с ошибкой, что нет метода для NilClass.
Оно и понятно, но вот простого решения что-то с ходу придумать не могу, чтобы присваивать значение при наличии ключа и nil при его отсутствии.
Вариант с if пока не рассматриваю. Ибо десятки if-ов не особо кошерно. Оборачивать в методы - ну тоже хрен знает.
Метод ||= тоже вроде не подходит, ибо присваивает значение только если переменная == nil.
В общем предлагайте варианты. :oops:
 
Оберни всё в трай-кетчи или используй короткие условия, которые есть почти во всех языках, вот, например, в js:
Код:
value = (array['item']) ? (array['item']['subitem'] || null) : null;
Ну а вообще, условиями будет более ли менее читабельно.
Лучше, конечно, привести конкретный код обработки массива - может быть у кого-нибудь получится переоформить код более удачно, чем сейчас.
 
  • Заблокирован
  • #3
хм... а почему не сделать
value = null;

if (array['item']) {
value = array['item']['value'];
}

это явно лучше чем if и else ибо если item пуст то условие пропускается и не тратится время на вызов else ибо value был присвоен ранее
 
хм... а почему не сделать
value = null;

if (array['item']) {
value = array['item']['value'];
}

это явно лучше чем if и else
Т.е. ты мне предлагаешь на каждый ключ if вешать, да? :eek:
Пока он один такой - еще ладно, но когда их десяток, то ну его в пень такое счастье.
Да и твой вариант можно сделать чуть проще:
Код:
value = array['item']['value'] unless array['item'].empty?
 
  • Заблокирован
  • #5
любопытно что твой вариант это тот же хрен только в другой руке, тоже самое что и из этого Для просмотра ссылки Войди или Зарегистрируйся по сути это те же is else только пишется короче.

Мне вот интересно каким чудным образом бы хочешь обойти не вешая if на ключик который хочешь проверить.

И да в руби я абсолютно не шарю
 
любопытно что твой вариант это тот же хрен только в другой руке, тоже самое что и из этого Для просмотра ссылки Войди или Зарегистрируйся по сути это те же is else только пишется короче.

Мне вот интересно каким чудным образом бы хочешь обойти не вешая if на ключик который хочешь проверить.

И да в руби я абсолютно не шарю
А я и не говорил, что он чем-то отличается. Но визуально он проще для меня.
Можно писать условия без использования if, например через массивы, если конечно уметь это делать.
Мне интересны разные варианты и не особо важно, на чем (почти не важно...)
 
  • Заблокирован
  • #7
А я и не говорил, что он чем-то отличается. Но визуально он проще для меня.
Можно писать условия без использования if, например через массивы, если конечно уметь это делать.
Мне интересны разные варианты и не особо важно, на чем (почти не важно...)

для меня стало визуально проще писать через ? : но это в js и php, даже не знаю если ли такое в руби, видимо в руби та запись которую ты привел аналогична этой записи.

Честно скажу условия через массивы не когда не делал, возможно оно и будет быстрее работать, но привычнее if для меня.
 
Решение найдено. Т.к. стандартный метод #merge не умеет в рекурсию, это нужно делать самому.
Пример реализации был подсмотрен в rails.
Чтобы не проверять постоянно ключи на их наличие в хэше, используется совмещение полученного хэша с шаблоном.
Отсутствующие ключи добавляются в хэш с пустыми значениями.
Код:
hash_one = {'title' => nil, 'meta' => {'seo' => nil, 'description' => nil}, 'contact' => {'phone' => nil, 'email' => nil, 'jabber' => nil}}
hash_two = {'title' => 'Hello', 'content' => 'null', 'contact' => {'phone' => 1234567890, 'email' => 'mail@example.com'}}

class Hash
        def deep_merge(hash)
                self.merge!(hash) do |key, old, new|
                        next old.deep_merge(new) if (old.is_a?(Hash) && new.is_a?(Hash))
                        new == 'null' ? old : new
                end
        end
end
p hash_one.deep_merge(hash_two)
 
Последнее редактирование:
merge хорошее решение.

Еще вот такую функцию заценил Для просмотра ссылки Войди или Зарегистрируйся
Вызываем:
PHP:
$value = getValue($versions, ['item', 'value'], 'defaulValue');
Если array['item'] или array['item']['value'] не существуют - вернёт строку 'defaulValue'. Очень удобно для пользовательского ввода и для одноуровневого массива нагляднее чем тернарный оператор "?":
 
Собственно пришлось переделать немного код, ибо не обрабатывались хэши вложенные в массивы.
Примеры:
Hash_1:
Код:
hash_one = {
        'title' => nil,
        'description' => nil,
        'comment_list' => [
                {
                        'comments' => [
                                {
                                        'author' => nil,
                                        'date' => nil,
                                        'comment' => nil
                                }
                        ]
                }
        ],
        'content' => nil
}
Hash_2:
Код:
hash_two = {
        'title' => 'Hello World!',
        'comment_list' => [
                {
                        'comments' => [
                                {
                                        'author' => 'Admin',
                                        'comment' => 'Default'
                                }
                        ]
                }
        ]
}
Например хеш, находящийся в 'comment_list' не обрабатывался. Т.е. 'date' не добавлялся в Hash_2.
Новый код вроде как этот тестовый кусок обрабатывает как надо. Вот он:
Код:
class Hash
        def deep_merge(hash)
                puts "self[0]: #{self}\nhash[0]: #{hash}"
                hash.merge!(self) do |key, v1, v2|
                        puts "key[0]: #{key}\nv1[0]: #{v1}\nv2[0]: #{v2}"
                        if v2.is_a?(Array)
                                v2.each do |array|
                                        v1[0].deep_merge(array)
                                end
                        else
                                puts ">> Return v2"
                                v2
                        end
                end
        end

end
Соответственно вызываем код:
Код:
p hash_two.deep_merge(hash_one)
А вот результат работы:
Код:
laptop% ruby -w merge.rb

--------------------
self[0]: {"title"=>"Hello World!", "comment_list"=>[{"comments"=>[{"author"=>"Admin", "comment"=>"Default"}]}]}
hash[0]: {"title"=>nil, "description"=>nil, "comment_list"=>[{"comments"=>[{"author"=>nil, "date"=>nil, "comment"=>nil}]}], "content"=>nil}
key[0]: title
v1[0]:
v2[0]: Hello World!
>> Return v2
key[0]: comment_list
v1[0]: [{"comments"=>[{"author"=>nil, "date"=>nil, "comment"=>nil}]}]
v2[0]: [{"comments"=>[{"author"=>"Admin", "comment"=>"Default"}]}]
self[0]: {"comments"=>[{"author"=>nil, "date"=>nil, "comment"=>nil}]}
hash[0]: {"comments"=>[{"author"=>"Admin", "comment"=>"Default"}]}
key[0]: comments
v1[0]: [{"author"=>"Admin", "comment"=>"Default"}]
v2[0]: [{"author"=>nil, "date"=>nil, "comment"=>nil}]
self[0]: {"author"=>"Admin", "comment"=>"Default"}
hash[0]: {"author"=>nil, "date"=>nil, "comment"=>nil}
key[0]: author
v1[0]:
v2[0]: Admin
>> Return v2
key[0]: comment
v1[0]:
v2[0]: Default
>> Return v2
{"title"=>"Hello World!", "description"=>nil, "comment_list"=>[{"comments"=>[{"author"=>"Admin", "date"=>nil, "comment"=>"Default"}]}], "content"=>nil}
Нули в квадратный скобках я указывал чисто для себя. Чтобы в случае неоднократного вывода self или hash в консоль, можно было вбить индексы и по коду смотреть, где какой индекс какое значение выводил.
Так вот, код работает. Почти...Загвоздка заключается в том, что если у нас массив, содержащий несколько хешей (например comment_list будет содержать 2 и более comments), то код опять будет падать с ошибкой на всех последующих итерациях. Так как в шаблоне только один comments. Все остальные хеши из hash_two будут мержиться с nil, а не с hash.
Вывод: Слать далеко и на долго геморойщиков с такими JSON-массивами, в которых ключи то есть, то их нет, то используются массивы, с неограниченной вложенностью и хз каким их количество. Не стоит оно того. с*ки...
 
Назад
Сверху