Опубликован: 27.07.2006 | Доступ: свободный | Студентов: 3174 / 531 | Оценка: 4.28 / 4.13 | Длительность: 26:56:00
Специальности: Программист
Лекция 11:

Введение в ООП

< Лекция 10 || Лекция 11: 123456789

Циклы

Для задания повторяющихся действий в большинстве языков программирования используются операторы цикла. В Ruby имеется два таких оператора - while и until, а также большое количество итераторов.

Оператор while выполняет операторы, составляющее его тело, ноль или более раз, до тех пор, пока истинно его условие, задаваемое некоторым логическим выражением. Его общий вид таков:

while <выражение> [do]
        ...
     тело цикла
        ...
end

Другим оператором цикла является until, выполняющийся до тех пор, пока его условие ложно:

until <выражение> [do]
        ...
     тело цикла
        ...
end

Пример Рассмотрим программу, печатающую числа от 1 до 5. Сначала используем оператор while, затем until. Обратите внимание, что условие окончания одного оператора цикла является отрицанием условия другого оператора.

i=1
while i <= 5
  puts i; i += 1
end

# еще раз
i=1
until i > 5
  puts i; i += 1
end

Кроме этих двух операторов цикла в Ruby имеется большое число, так называемых, итераторов (iterate - повторять). Давайте посмотрим на примеры их использования. Конструкция

3.times do
   print "Ау! "
end

использует итератор times. Цикл, заданный таким образом, выполнится ровно три раза.

В случае, когда нужно выполнить некоторые действия, зависящие от изменяемой величины, несколько раз, можно использовать итератор upto, так в процессе выполнения программы

0.upto(9) do |x| print x, " " end

будет напечатано 0 1 2 3 4 5 6 7 8 9.

Повтор от 0 до 12 с шагом 3 можно записать при помощи итератора step:

0.step(12, 3) {|x| print x, " " } # 0 3 6 9 12

При работе с массивами удобно использовать итератор each:

[1, 1, 2, 3].each {|k| print k, " " } # 1 1 2 3

Итератор for in очень похож на each, например, вывод, полученный в результате выполнения следующих двух конструкций одинаков.

for i in  ["one", "two", "three"]
  print i, " "
end

# то же самое
["one", "two", "three"].each{ |i| print i, " "}

Итератор for обычно используют там же, где и итератор each - при работе с массивами и диапазонами. Общий вид оператора for таков:

for <переменная> in <выражение> [do]
   тело_итератора
end

Пример

Перепишем программу печати чисел от 1 до 5 с использованием оператора for:

for i in 1 .. 5
  puts i
end

В этом примере мы снова воспользовались оператором задания диапазона .. (двоеточие), который позволил нам создать список чисел от 1 до 5 (включительно). Похожий оператор ... (троеточие) при создании диапазона не включает в него правый операнд. Фрагмент программы, расположенный ниже, эквивалентен предыдущему.

for i in 1 ... 6
  puts i
end

Пример

Рассмотрим несколько вариантов программы, вычисляющей факториал введенного числа.

  1. Использование оператора while
    print "Введите целое положительное число: "
    str = gets.chop! # ввели строку
    num = str.to_i   # преобразовали в число
    if num > 0
      i = 1
      fact = 1
      while i <= num
        fact *= i
        i += 1
      end
      puts "Факториал числа #{num} равен #{fact}"
    else
      puts "Вы ввели неположительное число"
    end
  2. Использование оператора for
    print "Введите целое положительное число: "
    num = gets.to_i # строку сразу преобразовали в число
    if num > 0
      fact = 1
      for i in 1 .. num
        fact *= i
      end
      puts "Факториал числа #{num} равен #{fact}"
    else
      puts "Вы ввели неположительное число"
    end
  3. Использование функции для определения факториала
    def fact(n)
      f = 1
      1.step(n,1) {|k| f *= k}
      return f
    end
    print "Введите целое положительное число: "
    if (num = gets.to_i) > 0
      print "#{num}! = #{fact(num)}\n"
    else
      puts "Факториал числа #{num} не определен\n"
    end

В последнем примере мы оформили вычисление факториала в виде функции и использовали итератор step, который обеспечил изменение переменной k с шагом 1.

Пример

Приведенная ниже программа запрашивает целое положительное число и определяет количество цифр в нем (обратите внимание на множественное присваивание).

print "Введите целое положительное число: "
a, k = gets.to_i, 0
while a>0
  a /= 10; k += 1 # отбросили последнюю цифру
end
print "Количество цифр в введенном числе равно #{k}.\n"

Пример

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

  1. Сначала введем количество элементов массива, а затем заполним его элементами, одним за другим. Обратите внимание, что первый элемент массива имеет индекс 0, а последний - на единицу меньший, чем размерность массива.
    print "Введите число элементов массива: "
    sn = gets.chop!; n = sn.to_i
    b = Array.new(n)   # создали массив из n элементов  
    s = 0              # обнулили сумму
    for i in 0 .. n - 1
      print "Введите #{i+1}-й элемент массива: "
      b[i] = gets.chop!.to_f; s = s + b[i]
    end
    print "Сумма всех элементов массива равна ", s, "\n"
  2. В этой версии программы все числа вводятся сразу в виде одной строки, в которой числа отделяется друг от друга пробелом (например, 23 -34.67 100.5).

Встроенный метод split разделяет строку на элементы массива, аргументом этого метода является разделитель (если разделителем является пробел, то можно вызвать этот метод без аргумента). Таким образом, если бы мы договорились разделять числа, например, точкой с запятой, то вызов метода выглядел бы так: a.split(';').

Для определения длины массива мы применили метод length (можно заменить на эквивалентный ему метод size ).

puts "Введите массив чисел (разделяя их пробелами):"
a = gets.chop!
b = a.split # разбили строку на отдельные числа
s = 0
for i in 0 .. b.length - 1
  s += b[i].to_f
end
puts "Сумма всех элементов массива равна #{s}"

В Ruby имеются четыре конструкции, задаваемые ключевыми словами break, redo, next и retry, которые изменяют обычный порядок выполнения циклов. Их действие описано в следующей таблице.

break Немедленно прекращает выполнение цикла; управление передается на утверждение, расположенное сразу за циклом
redo Повторяет тело цикла с начала, не пересчитывая условие выполнения цикла (не переходя к следующему элементу в случае итератора)
next Пропускает часть тела цикла, следующую за ним, и переходит к следующей итерации
retry Начинает выполнение цикла с самого начала

Рассмотрим на примере итератора for действие указанных конструкций.

for i in 1 .. 5
  print  i
  break if i == 3
  print "*"
end
Результат: 1*2*3
for i in 1 .. 5
  print  i
  redo if i == 3
  print "*"
end
Результат: 1*2*33333 ... выполнение цикла не прекращается
for i in 1 .. 5
  print  i
  next if i == 3   
  print "*"
end
Результат: 1*2*34*5*
for i in 1 .. 5
  print  i
  retry if i == 3
  print "*"
end
Результат: 1*2*31*2*31*2*... выполнение цикла не прекращается

Пример

Следующая программа начинает повторение цикла сначала, если при вводе указать символ y.

for i in 1 .. 5
  print "Now at #{i}. Restart?(y/n) "
  retry if gets.chop == "y"
end

Вот один из возможных вариантов выполнения этой программы:

Now at 1. Restart?(y/n) n
Now at 2. Restart?(y/n) y
Now at 1. Restart?(y/n) n
        ...
#!/usr/bin/env ruby
i=1
while i <= 5
  puts i; i += 1
end
puts

# еще раз
i=1
until i > 5
  puts i; i += 1
end
puts

3.times do
   print "Ау! "
end
puts

0.upto(9) do |x| print x, " " end 
puts

0.step(12, 3) {|x| print x, " " } # 0 3 6 9 12
puts

[1, 1, 2, 3].each {|k| print k, " " } # 1 1 2 3 
puts

for i in  ["one", "two", "three"]
  print i, " "
end
puts

# то же самое
["one", "two", "three"].each{ |i| print i, " "}
puts

for i in 1..5
  puts i
end
puts

for i in 1 ... 6
  puts i
end
puts

print "Введите целое положительное число: "
str = gets.chop! # ввели строку
num = str.to_i   # преобразовали в число
if num > 0
  i = 1
  fact = 1
  while i <= num
    fact *= i
    i += 1
  end
  puts "Факториал числа #{num} равен #{fact}"
else
  puts "Вы ввели неположительное число"
end
puts

print "Введите целое положительное число: "
num = gets.to_i # строку сразу преобразовали в число
if num > 0
  fact = 1
  for i in 1 .. num
    fact *= i
  end
  puts "Факториал числа #{num} равен #{fact}"
else
  puts "Вы ввели неположительное число"
end
puts

def fact(n)
  f = 1
  1.step(n,1) {|k| f *= k}
  return f
end
print "Введите целое положительное число: "
if (num = gets.to_i) > 0
  print "#{num}! = #{fact(num)}\n"
else
  puts "Факториал числа #{num} не определен\n"
end

puts
print "Введите целое положительное число: "
a, k = gets.to_i, 0
while a>0
  a /= 10; k += 1 # отбросили последнюю цифру
end
print "Количество цифр в введенном числе равно #{k}.\n"
puts

print "Введите число элементов массива: "
sn = gets.chop!; n = sn.to_i
b = Array.new(n)   # создали массив из n элементов  
s = 0              # обнулили сумму
for i in 0 .. n - 1
  print "Введите #{i+1}-й элемент массива: "
  b[i] = gets.chop!.to_f; s = s + b[i]
end
print "Сумма всех элементов массива равна ", s, "\n"
puts

puts "Введите массив чисел (разделяя их пробелами):"

a = gets.chop!
b = a.split # разбили строку на отдельные числа
s = 0
for i in 0 .. b.length - 1
  s += b[i].to_f
end
puts "Сумма всех элементов массива равна #{s}"
puts

=begin

for i in 1 .. 5
  print  i
  break if i == 3
  print "*"
end
puts


for i in 1 .. 5
  print  i
  redo if i == 3
  print "*"
end
puts

for i in 1 .. 5
  print  i
  next if i == 3   
  print "*"
end
puts

for i in 1 .. 5
  print  i
  retry if i == 3
  print "*"
end
puts

=end

for i in 1 .. 5
  print "Now at #{i}. Restart?(y/n) "
  retry if gets.chop == "y"
end
puts
Пример 1.8.

Задания

  1. Напишите программу, вычисляющую сумму всех четных натуральных чисел, не превосходящих 1000.
  2. Напишите программу, определяющую максимальный элемент массива чисел.
< Лекция 10 || Лекция 11: 123456789
Светлана Овчаркина
Светлана Овчаркина
Елена Митющенко
Елена Митющенко
И какова взаимосвязь между информацией и данными?