02. Числови типове. Масиви. Речници

02. Числови типове. Масиви. Речници

02. Числови типове. Масиви. Речници

12 октомври 2016

Какво предстои

днес и в следващите няколко лекции

С-бира-не

сряда

Първа задача

Правила на Кент Бек за прост и ясен дизайн

My guiding light is Kent Beck's rules of Simple Design (източник):

  1. The code must first be correct (as defined by tests);
  2. then it should be a clear statement of the design (what J.B.Rainsberger calls "no bad names");
  3. then it should contain no duplication (of text, of ideas, or of responsibility);
  4. and finally it must be the smallest code that meets all of the above.

It's time to stop refactoring when the code makes a reasonable stab at meeting those goals, and when any further changes would add no further benefit.

Тоест...

Малко въпроси

Въпрос 1

Кои от следните стойности ще се оценят до истина?

true
""
nil
[]
:baba
  • Всички без nil.

Въпрос 2

Какво ще изведе на екрана следната програма:

life_gives_you = 'lemons'
make = life_gives_you

make[5] = 'a'
make << 'de'

puts "When life gives you #{life_gives_you}"
puts "Make #{make}"
When life gives you lemonade
Make lemonade

Въпрос 3

По какво се различават имената в следните три реда:

variable = 1
Variable = 1
$variable = 1
  • Първото е локална променлива
  • Второто е константа
  • Третото е глобална променлива

Условия

кратък преговор

if !foo
  bar
elsif baz
  qux
else
  norf
end

bar if not foo
bar unless foo

Методи

още преговор

def max(a, b)
  a > b ? a : b
end

max(1, 5) # => 5

Изрази

В Ruby всичко може да се разглежда като израз, който си има оценка (стойност).

42            # => 42
x = 'files'   # => "files"
def foo() end # => :foo

Равенство

В Ruby има четири оператора за равенство

one == two      # сравнява по стойност
one === two     # специален оператор, който се използва в case
one.eql? two    # сравнява по стойност и тип
one.equal? two  # връща true, само ако one и two са един и същ обект

Типове данни

Досега говорихме за:

Числа

Числова йерархия

Това малко ще се промени в Ruby 2.4

Рационални числа

Комплексни числа

И такъв вграден тип има, Complex (документация):

Complex(1)           # => (1+0i)
Complex(2, 3)        # => (2+3i)
Complex('0.3-0.5i')  # => (0.3-0.5i)
Complex('2/3+3/4i')  # => ((2/3)+(3/4)*i)

3.to_c               # => (3+0i)
0.3.to_c             # => (0.3+0i)
'0.3-0.5i'.to_c      # => (0.3-0.5i)
'2/3+3/4i'.to_c      # => ((2/3)+(3/4)*i)
'1@2'.to_c           # => (-0.4161468365471424+0.9092974268256817i)

Кратко проучване

Колко от вас са запознати със следните неща:

Минимално необходимо знание за всеки програмист. Поставете си го за цел.

Отклониение

#to_s и #inspect

Един обект се обръща до низ с #to_s. Има и друг вариант, #inspect, който го обръща до текстов низ, изглеждащ като ruby код. Целта е инспектиране.

Преди това

хилядите значения на диез

Масиви

Масиви

индексиране

numbers = [:zero, :one, :two]
numbers[1]   # => :one
numbers[10]  # => nil
numbers[-1]  # => :two

numbers[5] = :five
numbers[5]   # => :five
numbers      # => [:zero, :one, :two, nil, nil, :five]

Масиви

fetch

Array#fetch хвърля грешка или връща друга стойност при индексиране извън обема на масива:

numbers = [:zero, :one, :two]

numbers.fetch(1)            # => :one

numbers.fetch(10)           # => error: IndexError
numbers.fetch(10) { |n| puts "#{n} isn't in array" } # вместо IndexError, се изпълнява кодът между { }

numbers.fetch(10, :dunno)   # => :dunno
numbers[10] or :dunno       # като предното, ама не точно

Ползва се по-рядко, отколкото си мислите.

Масиви

типичните методи

numbers = [3, 1, 2, 4]
numbers.length  # => 4
numbers.size    # => 4
numbers.sort    # => [1, 2, 3, 4]
numbers.reverse # => [4, 2, 1, 3]
numbers[1..2]   # => [1, 2]

sort и reverse връщат нов масив, без да променят numbers.

Масиви

#include?

#include? ви казва дали масив съдържа даден елемент.

prime_digits = [2, 3, 5, 7]

prime_digits.include? 2    # => true
prime_digits.include? 4    # => false

Внимание: линейно търсене. Подходящо за малки списъци.

Масиви

забавни оператори

[:a, :b, :c] + [:d, :e]             # => [:a, :b, :c, :d, :e]
[:a, :b, :c, :b, :a] - [:b, :c, :d] # => [:a, :a]
[:a, :b, :c] & [:b, :c, :d]         # => [:b, :c]
[:a, :b, :c] | [:b, :c, :d]         # => [:a, :b, :c, :d]

& и | конкатенират списъците и премахват повторенията.

В Ruby има множества, които са по-удачни в повечето случаи.

Масиви

мутиране

numbers = [1, 2, 3]

numbers << 4
p numbers   # => [1, 2, 3, 4]

numbers.insert 0, :zero
p numbers   # => [:zero, 1, 2, 3, 4]

result = numbers.delete_at(0)
p result    # => :zero
p numbers   # => [1, 2, 3, 4]

Масиви

push и pop

stack = [1, 2, 3]

stack.push 4
p stack         # => [1, 2, 3, 4]

top = stack.pop
p stack         # => [1, 2, 3]
p top           # => 4

#shift и #unshift са аналогични, но работят с началото на масива.

Масиви

разни други методи

[1, 2, 3].join("-")        # => "1-2-3"
[1, 2, 3].permutation      # сещате се какво връща
[1, 2].product([3, 4])     # => [[1, 3], [1, 4], [2, 3], [2, 4]]
[[1, 2], [3, 4]].transpose # => [[1, 3], [2, 4]]
[1, 2, 3, 4].shuffle       # разбърква масива произволно

Има редица такива методи, които може да намерите в Ruby Doc.

Масиви

последната запетая

Може да оставите запетая след последния елемент на масива. Така редовете се разместват по-лесно. Важи и за хешове.

songs = [
  'My Favorite Things',
  'Alabama',
  'A Love Supreme',
]

Масиви

пърладжийски истории

Има специален синтаксис за масив от думи.

%w(chunky bacon)     == ['chunky', 'bacon']
%w[a b c]            == ['a', 'b', 'c']
%w{cool stuff}       == ['cool', 'stuff']
%w<coffee tea water> == ['coffee', 'tea', 'water']
%w|foo bar|          == ['foo', 'bar']

Може да използвате различни видове символи, които да ограждат думите от масива:

! @ # $ * - _

Този списък от символи е непълен.

Масиви

Array#slice voodoo

Масиви

Array#slice

numbers = [1, 2, 3, 4, 5, 6]

numbers[0..2]   # => [1, 2, 3]
numbers[-3..-1] # => [4, 5, 6]
numbers[1, 1]   # => [2]

numbers[0..2] = [:wat]

numbers         # => [:wat, 4, 5, 6]

Масиви

итерация

Итерира се с #each, както всичко останало в Ruby:

primes = [2, 3, 5, 7, 11]

primes.each { |n| puts n }

primes.each do |n|
  puts n
end

Sidenote: for

...или как да губим точки

"Къдрави скоби" и do/end

Хешове

Хешове

общи факти

Хешове

индексиране

numbers = {:one => :eins, :two => :zwei}

numbers[:one]     # => :eins
numbers[:three]   # => nil

numbers[:three] = :drei

numbers[:three]                     # => :drei
numbers.fetch(:four, :keine_ahnung) # => :keine_ahnung
numbers.fetch(:four)                # => error: KeyError

Хешове

итерация

numbers = {:one => :eins, :two => :zwei}
numbers.keys    # => [:one, :two]
numbers.values  # => [:eins, :zwei]

numbers.each { |pair| puts pair }
numbers.each { |key, value| puts key, value }

Хешове

разни методи

numbers = {1 => 2, 3 => 4}

numbers.key?(:three) # => false
numbers.size             # => 2
numbers.invert           # => {2=>1, 4=>3}
numbers.merge({5 => 6})  # => {1=>2, 3=>4, 5=>6}
numbers.to_a             # => [[1, 2], [3, 4]]
Hash[1, 2, 3, 4]         # => {1=>2, 3=>4}

Хешове

алтернативен синтаксис

Долните два реда произвеждат еднакви хешове. Второто е 1.9+ синтаксис и ще предпочитаме него по конвенция (когато може):

{:one => 1, :two => 2}
{one: 1, two: 2}

Има интересна врътка при извикването на методи, за която ще споменем малко по-натам.

Списъци и хешове

накратко

Въпроси