2013-11-16 4 views
0

У меня есть следующий хэш:Извлечение данных из сложной хэш

def menu 
    { 
    diet: @diet, 
    proteins: ["Tofurkey", "Hummus"], 
    veggies: [:ginger_carrots, :potatoes, :yams], 
    desserts: { 
     pies: [:pumpkin_pie], 
     other: ["Chocolate Moose"], 
     molds: [:cranberry, :mango, :cherry] 
    } 
    } 
end 

Я хочу, чтобы извлечь десерты из хэша, а затем сформировать строку, которая говорит

«Сегодня у нас есть 5 вкусные десерты : Pumpkin Pie, шоколадный лосось и 3 формы: клюква, манго и вишня ».

У меня есть следующий код:

def whats_for_dessert 
    "Tonight we have 5 delicious desserts:" + 
    menu[:desserts][:pies].flatten.to_s + 
    menu[:desserts][:other].to_s 
end 

Этот код выводит

"Tonight we have 5 delicious desserts:[:pumpkin_pie][\"Chocolate Moose\"]" 

Есть ли лучший способ для сбора данных, так что я не в конечном итоге с кучей неудобных символов?

+0

Не используйте массив для пирогов? Например, присоединитесь к запятой, конвертируйте из символа в строку и сделайте ее доступной для чтения человеком? Не использовать символы для представления удобочитаемых данных? –

+0

Как было предложено правильно продумывать структуру данных для требуемой цели. Я предлагаю обернуть виды еды в классе, используя все форматированные методы вывода. Чистый дизайн с самого начала может спасти вас от множества избыточных работ и головных болей. –

+0

@DaveNewton, почему вы не можете опубликовать его в качестве ответа? –

ответ

1

Похоже, вы получили какие-то уступки. Хорошо практиковать использование ужасно структурированных данных, так как каждый раз вы используете чужой код (который вы не можете изменить!), Который выводит действительно неудобные структуры, подобные тому, с которым вы имеете дело.

Вы могли бы рассмотреть написание метода, как следующее:

def render_desserts(desserts_hash) 
    message = "Tonight we have #{desserts_hash.values.flatten.size} delicious desserts: " 
    msg_arry = desserts_hash.map do |key, array| 
    if array.length > 1 
     "#{array.length} #{key}: #{array.map(&:capitalize).join(' and ')}" 
    else 
     array[0].to_s.split(/[ _]/).map(&:capitalize).join(' ') 
    end 
    end 
    msg_arry[-1] = "and " + msg_arry[-1] 
    message += msg_arry.join(', ') 
end 

, которая печатает точно то, что вы просили напечатать в первоначальном назначении, если вы запустите

puts render_desserts(menu[:desserts]) 
+0

Но если бы данные немного изменились, мы получили бы что-то вроде «Сегодня вечером у нас есть 4 вкусных десерта: Pumpkin Pie, 2 other: Chocolate moose и Twinkies, и Cranberry', вероятно, не то, что желательно. Для этого необходимо много изменений, в том числе способ преобразования слов между единичным и множественным числом, как упоминалось в @rewritten, но я не думаю, что алерти просит об этом. –

+0

Вы правы, это назначение и, следовательно, ужасная структура данных. Я очень признателен вам за то, что вы объяснили, почему важно работать с плохими структурами данных - назначение представляло собой нечто вроде произвольного. В любом случае, ваш код совершенен, за исключением того, что он не помещает период в конце предложения, но я исправил это, спасибо! – trosborn

1

Вы могли бы сделать что-то вроде этого:

a = menu[:desserts].values.flatten 
puts "Tonight we have #{a.size} delicious desserts: #{a.map(&:to_s).join(', ').gsub('_',' ')}." 
    # => Tonight we have 5 delicious desserts: pumpkin pie, Chocolate Moose, cranberry, mango, cherry. 

но вы не должны иметь сочетание типов данных в ваших хэш-значений. Сделайте их все строки и все полное описание продукта:

def menu 
    { diet: @diet, proteins: ["Tofurkey", "Hummus"], 
    veggies: [:ginger_carrots , :potatoes , :yams], 
    desserts: ({ 
     :pies => ["pumpkin pie"], 
     :other => ["chocolate Moose"], 
     :molds => ["cranberry mold", "mango mold", "cherry mold"]})} 
end 

Затем измените puts на:

puts "Tonight we have #{a.size} delicious desserts:\n #{a.join(', ')}." 
=> Tonight we have 5 delicious desserts: 
=> pumpkin pie, chocolate moose, cranberry mold, mango mold, cherry mold. 
0

Вам нужен число десертов:

dessert_count = menu[:desserts].values.flatten.size 

Тогда (но это не очень понятно из ваших требований) вы хотите построить фразу из различных списков:

sentences = menu[:desserts].map { |kind, list| 
    case list.size 
    when 0 then "" 
    when 1 then "#{list[0]}".titleize 
    else  "#{list.size} #{kind.to_s.pluralize}: #{list.to_sentence.titleize}" 
      # 3 molds: Cranberry, Mango and Cherry 
    end 
end 

После того как вы это, вы можете создать свой окончательный приговор:

puts "Tonight we have #{dessert_count} delicious desserts: #{sentences.to_sentence}." 

Этот предполагается, что у вас есть active_support, который имеет очень полезные методы #to_sentence, #titleize и #pluralize.

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