---
title: "Основы программирования в R"
subtitle: "Условные конструкции и цикл `for`"
author: "Алла Тамбовцева, НИУ ВШЭ"
output:
  pdf_document: 
    toc: true
  html_document:
    df_print: paged
header-includes:
- \usepackage[russian]{babel}
- \usepackage{hyperref}
- \hypersetup{colorlinks = true, urlcolor = blue, linkcolor = magenta}
---

## Условные конструкции

Для того, чтобы в R осуществлял различные действия в зависимости от того, выполняется ли определённое условие или нет, понадобятся операторы условия: `if` и `else`. Например, мы сохраняем в R оценку по курсу и хотим, чтобы он выводил на экран "Good!" и "You are genius!!!", если она больше или равна 5 и "Bad!" — во всех остальных случаях.

```{r}
mark <- 2

if (mark >= 5){
  print("Good!")
  print("You are genius!!!")
}else{
  print("Bad.")
}
```

Само условие записывается в круглых скобках, а то, что R должен сделать в случае, если условие выполняется, перечисляется в фигурных скобках. Логика работы конструкции *if-else* ничем не отличается от Python, просто в R другой синтаксис, который требует наличие скобок вместо отступов. Если мы не поставим фигурные скобки, R не поймёт, что все строки выше, начиная с `print("Good!")` и заканчивая `print("Bad.")`, относятся к одному блоку кода, который нужно запускать сразу.

Если в случае выполнения условия R должен сделать что-то, что умещается в одну строчку кода, фигурные скобки можно опустить (и вообще всё записать в одну строчку):

```{r}
if (mark >= 5) print("Good.") else print("Bad.") 
```

Если необходимо применить несложную конcтрукцию *if-else* к каждому элементу вектора, можно воспользоваться функцией `ifelse()`. Сохраним вектор оценок `grades` и на его основе создадим вектор `grades_binary`, где 1 будет соответствовать оценкам выше 3, а 0 — всем остальным оценкам. 

```{r}
grades <- c(5, 7, 3, 4, 10, 8)
grades_binary <- ifelse(grades > 3, 1, 0)
grades_binary
```

В функции `ifelse()` на первом месте указывается условие, на втором — значение, которое должно возвращаться, если условие выполняется, на третьем — значение, которое должно возвращаться, если условие не выполняется. 

Иногда мы сталкиваемся с необходимостью использовать множественные условия, например, какие-то два условия должны выполняться одновременно. Для этого потребуются те же символы, которые используются в логических выражениях (`&` и `|`). Напишем код, который будет выдавать разные комментарии по оценке в 10-балльной шкале:

* оценка меньше 4: "Bad.";
* оценка не ниже 4, но ниже 6: "Not bad.";
* оценка не ниже 6, но ниже 8: "Good.";
* оценка не ниже 8, но не выше 10: "Excellent.";
* оценка выше 10: "We are the champions, my friend..." (R поет).

```{r}
mark <- 12
if (mark < 4) print("Bad.") else{
  if (mark >= 4 & mark < 6) print("Not bad.")
  if (mark >= 6 & mark < 8) print("Good.")
  if (mark >= 8 & mark <= 10) print("Excellent.")
  if (mark > 10) print("We are the champions, my friend...")
}
```


**Примечание:** конечно, здесь можно было бы обойтись и без вложенной конструкции *if-else*, но мы немного усложнили код, чтобы ещё раз потренироваться с постановкой различного вида скобок. 

А вот пример с оператором `|`, ситуация, когда мы выводим на экран "Excellent", если оценка или 8, или 9, или 10:

```{r}
if (mark == 8 | mark == 9 | mark == 10) print("Excellent")
```

Как можно заметить, так же, как и в Python, часть с `else` в условной конструкции здесь тоже является необязательной. 

Интересное отличие R от Python заключается в том, что здесь есть базовая функция, которая отвечает за логическую операцию XOR, исключающее «или». В то время как оператор `|` возвращает значение `True`, если хотя бы одно из условий верно, функция `xor()` возвращает значение `True`, если ровно одно из условий верно. 

Сравним: 

```{r}
# оба условия верны —> хотя бы одно верно —> True
3 < 5 | 7 < 9
```

```{r}
# оба условия верны —> неверно, что верно только одно —> False
xor(3 < 5, 7 < 9)
```

А вот в случае, когда только одно из условий верно, `xor()` вернет `True`:

```{r}
xor(3 < 5, 7 > 9)
```

## Цикл `for`

Чтобы повторять действия в R и при этом не копировать один и тот же код много раз, используются циклы. Существует два основных цикла: цикл `for` и цикл `while`. На практике чаще используется цикл `for`, потому что цикл `while` более специфический и более медленный (и программу с `while` очень легко зациклить).

Стоит также отметить, что для выполнения стандартных задач в рамках анализа данных в R циклы используются нечасто, так как в R многие операции векторизованы — функции применяются сразу к наборам значений, например, к векторам.

```{r}
# не нужно проходить по вектору x и возводить каждый элемент в квадрат
x <- c(1, 2, 3, 8)
x ** 2
```

Смысл цикла `for`: «для каждого элемента в наборе (векторе) сделай что-то». У нас есть вектор `v`, и мы хотим вывести его элементы на экран:

```{r}
v <- c(0, 1, NA, 0, 1)
for (i in v){
  print(i)
}
```

То, по чему итерируем (пробегаемся), указывается в круглых скобках, а то, что делаем в ходе цикла — в фигурных.

Для перебора можно задействовать последовательности:

```{r}
for (n in 1:10){
  print(n)
}
```

А теперь совместим цикл и условные конструкции. Вспомним про вектор оценок `grades`:

```{r}
grades
```

Выведем краткий комментарий на каждую из оценок:

```{r}

for (g in grades){
  if (g > 3) print("Pass")
  if (g <= 3) print("Fail")
}
```

