Папярэдні занятак

Масівы

Звычайна нам трэба захоўваць нашмат больш, чым проста адну рэч. Напрылад, што калі нам патрэбна захаваць сьпіс месяцаў у годзе?

  • months = ["january", "february", "march", "april", "may", "june", "july", "august", "september", "november", "december"]

Гэта завецца array (масіў).

Ніжэй тасама масівы. Паспрабуйце стварыць іх:

  • [2, 1, 17, 3327, 5, 69]
  • ["c", "o", "r", "s", "e", "b", "y"]
  • ["test", 42, "ololo", 123]

Зрабіце масівы з членамі вашае сямьі, любімымі лікамі і жывёламі, якіх вы найбольш баіцёся.

Вось яшчэ крыху прыгожых масіваў:

  • variable = "i'm variable"
  • [variable, "i'm just string"]
  • [32, 32 / 2]

Зрабіце некалькі масіваў якія маюць зьменныя й выразы ( 893/183 напрыклад).

А што калі мета-масівы?

  • ["radok", 42, ["jashche radok", 789], 531, "one more radok"]

Стварыце масівы, якія ўтрымліваюць іншыя масівы. Яшчэ лепей, калі масів утрымоўвае зьменныя з іншымі масівамі.

Элементы масіваў

Вы можаце атрымаць элемент з масіва вось так:

  • my_array = ["dog", "cat", "rabbit", "bee"]
  • my_array[3]

Лічба 3, якая кажа Ruby з якога месца трэба ўзяць элемент, завецца index.

Гэтак жа як і радкі, масівы пачынаюцца з нуля. Памятайце гэта!

У тых масіваў, якія Вы ўжо зрабілі паспрабуйце падаставаць якія-небудзь элементы.

Паспрабуйце з масівамі тыя апэрацыі, якія ёсьць у радкоў. Напрыклад дзьве лічбы ў квадратных дужках (т.б. my_array[2..3]) і адмоўныя індэксы. Будзе вельмі падобна на радкі :)

Апэрацыі з масівамі

Гэтак жа як і з радкамі, Вы можаце выкарыстоўваць апэратар << каб дадаваць элемэнты ў масіў:

  • my_array = []
  • my_array << "new element"
  • my_array

У параўнаньні з радком – shovel(рыдлёўка) – лепшы спосаб як дадаваць элемэнты ў масіў.

Паспрабуйце апэратар +. Падказка: Вы можаце складаць два масіва, але ня можаце складаць масіў і радок.

Мэтады масіваў

Зараз Вы ўжо здолееце зразумець як выклікаць мэтады ў масіва. Паспрабуйце даведацца што робяць гэтыя мэтады: sort, length, reverse, +, last, pop, push.

Яшчэ сінтаксічны цукар: апэратар shovel гэта сінтаксічны цукар мэтада push.

Варта праглядзець дакумэнтацыю Ruby для масіваў.

Масівы й радкі

Паспрабуйце:

  • "I am a web developer".split

І гэта:

  • "I,am,a,web,developer".split(",")

Па дэфолту, split выкарыстоўвае прабелы ў якасьці падзельніка (delimiter). Але Вы можаце перадаць любы падзяляльнік першым аргумэнтам.

Пагуляйце яшчэ з split. Паспрабуйце розныя падзяляльнікі.

Зараз паспрабуйце гэта:

  • ["Join", "me", "back!"].join(" ")

Што робіць гэты мэтад? Пагуляйце яшчэ зь імі выкарыстоўваючы розныя падзяляльнікі.

Мэтад each (кожны)

Зараз Вы ўжо маеце базавыя веды як працаваць з масівамі, таму давайце паспрабуем больш прасунуты канцэпт: looping (цыклы).

Наш калькулятар можа лічыць суму двух лікаў, а што калі мы хочам падлічыць некалькі? Мы будзем выкарыстоўваць мэтад each:

total = 0
summands = [1,2,3,4,5]
summands.each do |summand|
  total += summand
end
total

Гэта трошкі складана, таму давайце разьбярэмся што адбываецца:

  1. Ствараецца зьменная total са значэньнем 0.
  2. Ствараецца масіў лічбаў які завецца summands.
  3. Выклікаецца мэтад each у масіва summands.
  4. Бярэцца першы элемэнт з summands і зьменнай summand прызначаецца яго значэньне.
  5. У зьменную total дадаецца бягучы summand.
  6. 4 і 5 паўтараюцца для астатніх лікаў з summands.

Код, які знаходзіцца паміж do і end завецца block. Блок вельмі падобны на мэтад, толькі бяз назвы; зьменная паміж | як аргумэнт у мэтадзе.

Традыцыйна масіў называюць словам у множным ліку, а аргумэнт блока (у такім выпадку) ў адзіночным ліку (т.б. summands для масіва й summand для аргумэнта).

Зараз падыйшла Вашая чарга. Напішыце цыкл, які б лічыў вынік множаньня ўсіх лікаў у масіве. Павінна атрымацца вельмі падобна на код, які лічыць суму.

puts

Давайце прабяжымся па некаторым краінам і скажам якія яны маюць сталіцы:

  • countries_with_capitals = [['Belarus', 'Minsk'], ['US', 'Washington'], ['Bulgaria', 'Sofia']]
  • countries_with_capitals.each do |country_with_capital|
  • "The capital of #{country_with_capital[0]} is #{country_with_capital[1]}."
  • end
=> [["Belarus", "Minsk"], ["US", "Washington"], ["Bulgaria", "Sofia"]]

Нічога не атрымалася. Мы не атрымалі нічога акрамя першапачатковага масіва. Што здарылася?

Давайце паглядзім на код, які лічыць суму лікаў:

  • sum = 0
  • summands = [1,2,3,4,5]
  • summands.each do |summand|
  • sum += summand
  • end
  • sum

Што мэтад each насамрэч вярнуў? Атрымліваецца што ў абодвух выпадках ён вярнуў незьмянённы масіў. Дык як жа нам надрукаваць тое, што знаходзіцца ўнутры масіва?

Давайце даведаемся пра мэтад puts:

  • countries_with_capitals = [['Belarus', 'Minsk'], ['US', 'Washington'], ['Bulgaria', 'Sofia']]
  • countries_with_capitals.each do |country_with_capital|
  • puts "The capital of #{country_with_capital[0]} is #{country_with_capital[1]}."
  • end

Незьмянённы масіў усе так жа й вяртаецца, але puts друкуе кожную лінію на экран. Калі Вам цікава што такое puts – гэта глабальны мэтад. Дадайце дужкі аргумэнтам(т.б. puts('hi')) і Вам стане прасьцей гэта бачыць.

Пагуляйце з puts. Што будзе калі перадаць лічбу альбо масіў як аргумэнт?

Прабяжыцеся па масіву членаў вашае сямьі й скажыце кожнаму “Вітаньне!” .

map і (рэфактарынг) refactoring

(Рэфактарынг) Refactoring – гэта працэс паляпшэньня існуючага кода, без зьмяненьня зьнешніх інтэрфэйсаў. Пальпшэньне чатальнасьці, аптымізацыя прадукцыйнасьці і выдаленьне паўтарэньняў – прыклады рэфактарынга. Давайце напішем трошкі коду, даведаемся пра новы сінтакс і некалькі мэтадаў і ў рэшце адрэфактарым код.

Спачатку напішам мэтад які ўдвойвае значэньне кожнага ліка ў масіве:

def double(original_numbers)
  doubled_numbers = []
  original_numbers.each do |original_number|
    doubled_numbers << original_number * 2
  end
  return doubled_numbers
end

Першы рэфактарынг: шосты радок.

def double(original_numbers)
  doubled_numbers = []
  original_numbers.each do |original_number|
    doubled_numbers << original_number * 2
  end
  doubled_numbers
end

Значэньне апошняй лініі, якая знаходзіцца ў мэтадзе, заўсёды вяртаецца, нават калі й няма ключавога слова return. Рубісты рэдка карыстаюцца return і замест гэтага заўсёды карыстаюцца фактам таго, што апошняя лінія ўсё адно вяртаецца. З гэтага моманту мы такскма ня будзем пісаць return, а проста будзем ведаць, што падлічаннае значэньне апошняга радка вяртаецца.

Другі рэфактарынг: калі код паміж do і end толькі адзін радок, блок можа быць запісаны вось так:

def double(original_numbers)
  doubled_numbers = []
  original_numbers.each {|original_number| doubled_numbers << original_number * 2}
  doubled_numbers
end

Ну вось ужо выглядае лепей!

Выглядае трошкі напружна што мы павінны мець асобную зьменную doubled_numbers толькі для таго, каб захоўваць падвоеныя лікі. Было б файна калі each неяк вяртаў значэньні якія мы палічылі.

Для гэтага й патрэбен map:

def double(original_numbers)
  original_numbers.map {|original_number| original_number * 2}
end

original_numbers не зьмянілася (няма !, які кажа, што гэта дэструктыўны мэтад). Map проста бярэ ўсё што вяртаецца з блока й кладзе ў новы масіў.

Зараз гэты мэтад выглядае выдатна!

Пагуляйце яшчэ з map і сінтаксісам з фігурнымі дужкамі для each і map. Паспрабуйце выкарыстаць map каб прабегчыся па масіву радкоў і вярнуць іх з вялікімі літарамі.

inject і яшчэ рэфактарынг

Давайце разглядзім яшчэ адзін ітэратар (iterator) (так завецца мэтад, які бяжыць па масіву напрыклад each і map).

Вось як мы лічылі суму раней:

  • sum = 0
  • summands = [1,2,3,4,5]
  • summands.each do |summand|
  • sum += summand
  • end
  • sum

Спачатку, давайце перапішым мэтад каб ён прымаў масіў у якасьці аргумэнта:

  • def sum(summands)
  • total = 0
  • summands.each do |summand|
  • total += summand
  • end
  • total
  • end

Потым выкарыстаем сінтаксіс з фігурнымі дужкамі:

  • def sum(summands)
  • total = 0
  • summands.each {|summand| total += summand}
  • total
  • end

А зараз новы мэтад - inject. Карыстаемся ім:

  • def sum(summands)
  • summands.inject(0) {|total, summand| total += summand}
  • end

Паспрабуйце зразумець, што робіць inject. Спачатку яго будзе трошкі складана зразумець, але ён - лепшае рашэньня для выпадкаў калі Вам патрэбна зьмяніць значэньне нейкай зьменнай на кожнай ітэрацыі. Давайце разглядзім прыклад зsum([2,4,6]). Звярніце ўвагу што блок прымае на ўваход два аргумэнта: total і summand.

  1. summands усталёўваецца ў [2,4,6].
  2. inject выклікаецца ў summands.
  3. total усталёўваецца роўным 0 - першаму аргумэнту inject.
  4. summand усталёўваецца роўным нулявому элемэнту summands: 2.
  5. summand дадаецца да total: 0 + 2 = 2.
  6. inject рухаецца на наступную ітэрацыю цыкла. Новае значэньне total (2) "уводзіцца" ў наступную ітэрацыю, а summand усталёўваецца роўным наступнаму элемэнту масіва (4).
  7. Крокі 5 і 6 паўтараюцца для астатніх элемэнтаў масіва.
  8. Вяртаецца канчатковае значэньне total: 12.

Гэтак жа як і summand total гэта проста назва зьменнай, якую Вы можаце зьменіць на што пажадаеце ў залежнасьці ад абставін.

Калі Вы не перадаіце аргумэнт у inject, першы аргумэнт функцыю ўсталёўваецца роўным нулявому элемэнту масіва. Таму мы можам напісаць:

  • summands.inject {|total, summand| total += summand}

Пагуляйце яшчэ з inject. Выкарыстайце яго каб падлічыць вынік множаньня ўсіх элемэнтаў у масіве.

Дыяпазоны

Давайце створым масіў усіх элементаў паміж 1 і 100: [1,2,3,4,5,6,7,8,9,10,11,12,13]. Я стаміўся, а Вы? Павінен быць больш прасьцейшы спосаб гэта зрабіць.

Ён завецца дыяпазон (range). Дыяпазон паводзіць сябе вельмі падобна на масіў:

  • (1..100).inject {|total, summand| total += summand}

Вось мы й палічылі суму ўсіх лічбаў паміж 1 і 100.

Пагуляйце яшчэ з дыяпазонамі. Ці працуюць яны для літар? Надрукуйце альфабэ выкарыстоўваючы мэтад puts. Што будзе калі Вы дададзіце зьменную ў дыяпазон? А што будзе калі выкарыстоўваць тры кропкі замест дзьвух?

Наступны занятак