Втора задача - хешове, масиви и структура

Предадени решения

Краен срок:
24.10.2016 17:00
Точки:
6

Срокът за предаване на решения е отминал

Хешове, масиви и структура

Човек и добре да живее, рано или късно му се налага да преобразува данни от една форма в друга. В практиката често ни се налага да използваме данни от други системи. Например, може да ни се наложи да изтеглим данни от Facebook. В почти всички случаи тези данни са във форма, която не е напълно съвместима със системата, която пишем и трябва да се преобразуват.

Целта на тази задача е да напишем няколко метода, които ще са ни полезни в пренареждането на данни.

Дълбок достъп до ключове

Добавете метод fetch_deep към всички хешове, който приема един аргумент - път до стойността в хеша. Път до стойност наричаме последователност от ключове, които са разделени с точки.

Да вземем за пример този хеш:

order = {
  dessert: {
    type: 'cake',
    variant: 'chocolate',
    rating: 10,
    comments: [
      {text: 'So sweet!'},
      {text: 'A perfect blend of milk chocolate and cookies. With a cherry on top.'}
    ]
  }
}

Пътят към стойността 'chocolate' е dessert.variant. Методът fetch_deep трябва да проследи двата ключа (dessert и variant), и да върне стойността, асоциирана с последния.

Тоест, order.fetch_deep('dessert.variant') трябва да върне chocolate.

Разбира се, пътят може да се състои и само от един ключ - order.fetch_deep('dessert') #=> хешът с тортата.

Бележка: може да използвате self вътре в методите, за да достъпите обекта, върху който се извикват.

fetch_deep трябва да поддържа и ключове към масиви. В този случай вместо ключ на хеш може да има индекс на масив:

order.fetch_deep('dessert.comments.0.text') #=> "So sweet!"

Разбира се, няма как първият ключ да е индекс в масив, защото методът fetch_deep е дефиниран в Hash.

Ключовете на хешовете, които ще използваме може да са както символи, така и стрингове. За сметка на това, пътят винаги ще е стринг.

dessert = {
  type: 'cake',
  'variant' => 'chocolate'
}

dessert.fetch_deep('type')    #=> 'cake'
dessert.fetch_deep('variant') #=> 'chocolate'

Без значение е стойността на кой ключ ще върнете, ако в хеша има два ключа с едно и също име, но единият е стринг, а другият е символ.

Ако не съществува стойност с подадения път - върнете nil.

Преструктуриране на данни

Втората част от задачата е да добавите по един метод с име reshape към Array и Hash.

Hash#reshape

Добавете метод reshape на всички хешове, който преобразува текущия хеш в нов с различна структура. Методът приема единствен аргумент, който описва формата на резултата.

Ето как трябва да работи:

order = {
  dessert: {type: 'cake', variant: 'chocolate'}
}

shape = {
  food: 'dessert.type',
  taste: 'dessert.variant'
}

order.reshape(shape)
#=> {
#   food: 'cake',
#   taste: 'chocolate'
# }

Както вече се досетихте, ключовете на формата са ключовете, които трябва да съществуват в резултата. Стойностите на формата са пътища към стойностите от оригиналния хеш - аргументите на Hash#fetch_deep.

Hash#reshape трябва да може да конструира и "дълбоки" хешове:

order = {
  dessert: {type: 'cake', variant: 'chocolate'}
}

shape = {
  food: {type: 'dessert.type', taste: 'dessert.variant'}
}

order.reshape(shape)
#=> {
#   food: {type: 'cake', taste: 'chocolate'}
# }

Array#reshape

Напишете метод Array#reshape - аналогът на Hash#reshape, но за масиви:

inventory = [
  {item: {type: 'musaka', price: 4.0, quantity: 30}},
  {item: {type: 'cake',   price: 3.5, quantity: 20}}
]

shape = {food: 'item.type', price: 'item.price'}

inventory.reshape(shape)
#=> [
#   {food: 'musaka', price: 4.0},
#   {food: 'cake', price: 3.5}
# ]

Тук shape е видът, в който трябва да се преобразува всеки елемент на inventory. shape трябва да се държи като аргумент на Hash#reshape.

Други неща

Ако не разбирате нещо от условието - прочетете го отново и разгледайте примерите по-детайлно. Ако все още не ви е ясно нещо - пишете в темата за задачата във форума - ще помагаме!

Можете да ни пишете и ако имате проблеми с определена част от имплементацията - ще ви дадем насоки.

Не забравяйте да си пуснете примерните тестове преди да предадете решение. Успех!

Ограничения

Тази задача има следните ограничения:

  • Най-много 80 символа на ред
  • Най-много 3 нива на влагане
  • Най-много 8 реда на метод

Ако искате да проверите дали задачата ви спазва ограниченията, следвайте инструкциите в описанието на хранилището за домашните.

Няма да приемаме решения, които не спазват ограниченията. Изпълнявайте rubocop редовно, докато пишете кода. Ако смятате, че rubocop греши по някакъв начин, пишете ни на fmi@ruby.bg, заедно с прикачен код или линк към такъв като private gist. Ако пуснете кода си публично (например във форумите), ще смятаме това за преписване.