2015-09-16 2 views
0

У меня есть следующий JSON:Показать все значения для каждой даты в формате JSON

{ 
    "groups" : [ 
     { 
     "values": "21", 
     "date": "2013-02-22" 
     }, 
     { 
     "values": "25", 
     "date": "2013-02-22" 
     }, 
     { 
     "values": "20", 
     "date": "2013-02-22" 
     }, 
     { 
     "values": "19", 
     "date": "2013-02-22" 
     }, 
     { 
     "values": "42", 
     "date": "2013-02-10" 
     }, 
     { 
     "values": "30", 
     "date": "2013-02-10" 
     }, 
     { 
     "values": "11", 
     "date": "2013-02-10" 
     } 

    ] 
} 

У меня есть ценности и дата уже извлеченная в Рубиновом классе. Я хочу найти «наивысшее» и «самое низкое» значение для каждой даты. Как мне это сделать?

Также я хочу создать параллельные массивы для одного и того же. Например:

low = [12, 22, 11, 45] 
high = [34, 50, 15, 60] 
dates = ["2013-02-22", "2013-02-10", "2013-02-06", "2013-02-01"] 

Я также хотел бы отображать все значения для каждой даты.

Может кто-то, пожалуйста, дайте мне какое-то направление для этого?

+3

Что вы пытаетесь? Функция ['group_by'] (http://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-group_by) здесь очень полезна. – tadman

+1

Добро пожаловать в переполнение стека. Важно дать нам минимальные входные данные, ожидаемый результат и минимальный код, необходимый для воспроизведения проблемы, которую вы видите. Эта последняя часть, минимальный код, необходимый для воспроизведения проблемы, помогает нам НЕ попробовать все возможное, но сосредоточиться на том, как вы атакуете проблему. Как, кажется, вы не пробовали и не хотите, чтобы мы пытались за вас или объяснили, как это сделать, ни то, ни другое из того, как работает SO. –

+0

Когда вы приводите пример в вопросе (как правило, очень хорошо), важно, чтобы входные данные были действительными объектами Ruby. Как вы знаете, объекты JSON являются строками, поэтому вам нужно добавить одинарные кавычки '' {...} ''или использовать'% s [...] 'или heredoc. Кроме того, вы должны назначить все входные значения для переменных, поэтому они могут быть указаны в ответах и ​​комментариях без необходимости их определения. Например, 'str =' '{...}' '. –

ответ

1

str Если ваша строка JSON:

require 'json' 
arr = JSON.parse(str)["groups"] 
    #=> [{"values"=>"21", "date"=>"2013-02-22"}, 
    # {"values"=>"25", "date"=>"2013-02-22"}, 
    # {"values"=>"20", "date"=>"2013-02-22"}, 
    # {"values"=>"19", "date"=>"2013-02-22"}, 
    # {"values"=>"42", "date"=>"2013-02-10"}, 
    # {"values"=>"30", "date"=>"2013-02-10"}, 
    # {"values"=>"11", "date"=>"2013-02-10"}] 

by_date = arr.each_with_object(Hash.new {|h,k| h[k] = []}) { |g,h| 
    h[g["date"]] << g["values"].to_i } 
    # => {"2013-02-22"=>[21, 25, 20, 19], "2013-02-10"=>[42, 30, 11]} 

dates = by_date.keys 
    #=> ["2013-02-22", "2013-02-10"]  
min_vals, max_vals = *by_date.map { |_,vals| vals.minmax } 
    #=> [[19, 25], [11, 42]] 
min_vals 
    #=> [19, 25] 
max_vals 
    #=> [11, 42] 

Метод Enumerable#each_with_object принимает аргумент, который представляет собой первоначальное значение объекта, который будет построен и возвращаемым методом. Это значение задается второй блочной переменной, h. Я сделал этот аргумент пустой хэш-значение по умолчанию задается блоком:

{|h,k| h[k] = []} 

Что такое «значение по умолчанию»? Все это означает, что если хэш h не имеет ключа k, h[k] возвращает пустой массив. Давайте посмотрим, как это работает здесь.

Первоначально h #=> {} и each_with_object устанавливают первый переменный блок, g равных первое значение arr: выполняется

g = {"values"=>"21", "date"=>"2013-02-22"} 

и блок вычисления:

h[g["date"]] << g["values"].to_i 
    #=> h["2013-02-22"] << 21 

Поскольку h вовсе нет ключ "2013-02-22", h["2013-02-22"] сначала установлен равным значению по умолчанию, пустой массив:

h["2013-02-22"] = [] 

затем

h["2013-02-22"] << 21 
    #=> [21] 
h #=> {"2013-02-22"=>[21]} 

Когда следующее значение arr передается к блоку:

g = {"values"=>"25", "date"=>"2013-02-22"} 

и h, как указано выше. Так что теперь вычисление блока:

h[g["date"]] << g["values"].to_i 
    #=> h["2013-02-22"] << 25 
    #=> [21, 25] 
h #=> {"2013-02-22"=>[21, 25]} 

Значение по умолчанию не используется этот раз, как h имеет ключевое "2013-02-22".

одна вещь может потребовать объяснение: «восклицательный знак» * в:

min_vals, max_vals = *by_date.map { |_,vals| vals.minmax } 

Мы видим, что:

by_date.map { |date, vals| vals.minmax } 
    #=> [[19, 25], [11, 42]] 

Если *by_date.map { |date, vals| vals.minmax } находится на правой стороне равенства, то восклицательный знак причин два элемента из [[19, 25], [11, 42]] присваиваются переменным с левой стороны равенства, используя параллельное назначение. Странный и замечательный splat operator должен быть в сумке трюков Rubiest.

Поскольку я не использую date в расчете блока, я обратил на это внимание, заменив date на локальную переменную _.

Edit: Для того, чтобы ответить на вопрос, который вы размещены в комментарии, если:

id = [1,1,1,2,2,3,4] 
high = [100,100,100,90,90,100,100] 
low = [20,20,20,10,10,30,40] 

и я правильно понимаю ваш вопрос, вы могли бы сначала вычислить:

indices = id.each_with_index.to_a.uniq(&:first).map(&:last) 
    #=> [0, 3, 5, 6] 

Тогда три массива вы хотите:

id.values_at(*indices) 
    #=> [1, 2, 3, 4] 
high.values_at(*indices) 
    #=> [100, 90, 100, 100] 
low.values_at(*indices) 
    #=> [20, 10, 30, 40] 
+0

Отлично. Отлично сработано. Только то, что я бы разместил. 'by_date.map {| k, v | [k, v.minmax]} .to_h' также полезна. –

+0

Кэри, спасибо за ответ. Это действительно помогло. Что делать, если у меня уже есть значения high/low в json, и я могу создать массив с ним? Скажем, у меня есть 'high = [100,100,100,90,90,100,100] low = [20,20,20,10,10,30,40]'. Также у меня есть идентификатор для группы элементов. 'ID = [1,1,1,2,2,3,4]'. Как разбить это на основе идентификатора? Я хочу, чтобы результат был «high = [100, 90,100,100] low = [20, 10, 30, 40] id = [1,2,3,4]». – doesey

+0

Вы должны быть более конкретными. Наверное, лучше поставить другой вопрос. –

1

Вы можете group_by:date и повторяйте даты. Затем создайте массив из группы :values.

Затем используйте minmax, чтобы получить правильные значения и transpose окончательный массив, чтобы получить свои массивы и назначить даты, низкие и высокие.

json = { 
    "groups": [ 
    { "values": "21", "date": "2013-02-22" }, 
    { "values": "25", "date": "2013-02-22" }, 
    { "values": "20", "date": "2013-02-22" }, 
    { "values": "19", "date": "2013-02-22" }, 
    { "values": "42", "date": "2013-02-10" }, 
    { "values": "30", "date": "2013-02-10" }, 
    { "values": "11", "date": "2013-02-10" } 
    ] 
} 

dates, low, high = json[:groups].group_by { |g| g[:date] }.map do |date, grouped| 
    values = grouped.map { |group| group[:values] } 
    [date, *values.minmax] 
end.transpose 
# => => [["2013-02-22", "2013-02-10"], ["19", "11"], ["25", "42"]] 

dates 
# => ["2013-02-22", "2013-02-10"] 
low 
# => ["19", "11"] 
high 
# => ["25", "42"] 
+0

Помните, что OP является «новым для Ruby». –

+0

@CarySwoveland Я понимаю это, но я считаю, что кто-то новый для языка должен всегда читать документацию и попробовать все методы в ответах, чтобы узнать, что происходит и чему учиться. – Doguita

Смежные вопросы