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

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

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

12 октомври 2015

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

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

С-бира-не

сряда

Инсталиране на Ruby

последен срок за промоцията

Първа задача

Втора задача

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

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.

Условия

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

if not 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 са един и същ обект

Типове данни

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

Числа

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

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

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

И такъв вграден тип има, 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}

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

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

накратко

Въпроси