-
Notifications
You must be signed in to change notification settings - Fork 8
/
08-intro-to-expressions-conditionals.Rmd
477 lines (362 loc) · 9.92 KB
/
08-intro-to-expressions-conditionals.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
---
title: "Basics of R expressions and conditionals"
subtitle: "Stat 133"
author: "Gaston Sanchez"
output: github_document
fontsize: 11pt
urlcolor: blue
---
> ### Learning Objectives:
>
> - Understand the concept of R Expressions
> - Learn the difference between simple and compound expressions
> - Understand the use of braces to group expressions
> - Conditional structures: if-then-else, and `switch()`
------
## R Expressions
Before talking about conditional structures and loops, we must first talk
about __expressions__.
R programs are made up of expressions. These can be either _simple_ expressions
or _compound_ expressions. Compound expressions consist of simple expressions
separated by semicolons or newlines, and grouped within braces.
```r
# structure of a compound expression
# with simple expressions separated by semicolons
{expression_1; expression_2; ...; expression_n}
# structure of a compound expression
# with simple expressions separated by newlines
{
expression_1
expression_2
expression_n
}
```
Here's a less abstract example:
```{r}
# simple expressions separated by semicolons
{"first"; 1; 2; 3; "last"}
# simple expressions separated by newlines
{
"first"
1
2
3
"last"
}
```
Writing compound expressions like those in the previous example is not
something common among R users. Although the expressions are perfectly valid,
these examples are very dummy (just for illustration purposes).
I discourage you from grouping multiple expressions with semicolons because
it makes it difficult to inspect things. As for the expressions separated by
newlines, they do play an important role but they are typically used together
with other programming structures (e.g. functions, conditionals, loops).
### Every expression has a value
A fundamental notion about expressions is that
__every expression in R has a value__. If you have a simple expression like:
```{r}
a <- 5
```
then `a` has the value 5. In contrast, the value of a compound
expression is the value of the last evaluated expression.
Here's one example of a compund expression. Note that the entire expression is
assigned to `x`:
```{r}
x <- {5; 10}
```
- What is the value of `x`?
+ 5?
+ 10?
+ 5, 10?
In this case, the compound expression has a value of `10`, which was the last
expression inside the braces.
Here's the same compound expression as above, but now with simple expressions
in newlines:
```{r}
x <- {
5
10
}
x
```
To make sure you don't forget it, repeat this mantra:
> - Every expression in R has a value: the value of the last evaluated statement.
> - Every expression in R has a value: the value of the last evaluated statement.
> - Every expression in R has a value: the value of the last evaluated statement.
---
### Assignments within Compound Expressions
It is possible to have assignments within compound expressions and the
values of the variables which this produces can be used in later expressions.
```{r}
# simple expressions (made up of assignments) separated by newlines
{
one <- 1
pie <- pi
zee <- "z"
}
one
pie
zee
```
Here's another example:
```{r}
z <- { x = 10 ; y = x^2; x + y }
x
y
z
```
Now that we've introduced the concept of R expressions, let's introduce
conditional structures
---
## Conditionals
Every programming language comes with a set of structures that allows us to
have control over how commands are executed. One of these structures is called
__conditionals__, and as its name indicates, they are used to evaluate
conditions.
The most common conditional structure, conceptually speaking, is the
__if-then-else__ statement. This type of statement makes it possible to choose
between two (possibly compound) expressions depending on the value of a (logical) condition.
In R (as in many other languages) the if-then-else statement has the following
structure:
```r
if (condition) {
# do something
} else {
# do something else
}
```
As you can tell, the `if` clause works like a function: `if(condition)`.
Likewise, braces are used to group one or more expressions. If the condition
to be evaluated is true, then just the expressions inside the first pair of
braces are executed. If the condition is false, then the expressions inside
the second pair of braces are executed:
```{r}
x <- 1
if (x > 0) {
print("positive")
} else {
print("not positive")
}
```
For readability reasons, most users prefer to write `if (condition)` instead of
`if(condition)`. The _condition_ is an expression that when evaluated returns
a __logical__ value of length one. In other words, whatever you pass as the
input of the `if` clause, it has to be something that becomes `TRUE` or `FALSE`
```{r}
if (TRUE) {
print("TRUE")
} else {
print("FALSE")
}
```
```{r}
if (FALSE) {
print("TRUE")
} else {
print("FALSE")
}
```
#### Minimalist If-then-else
`if` statements can be written in different forms, depending on the types of
expressions that are evaluated. If the expressions of both the _True_ part and
the _False_ part are simple expressions, the if-then-else can be simplified as:
```r
if (condition) expression_1 else expression_2
```
With simple expressions there's actually no need to use braces:
```{r if1}
x <- 10
if (x > 0) y <- sqrt(x) else y <- -sqrt(-x)
y
```
The previous statement can be written more succinctly in R as:
```{r if2}
x <- 10
y <- if (x > 0) sqrt(x) else -sqrt(-x)
y
```
Again, even though the previous commands are perfectly OK, it is preferred to
use braces when working with conditional structures. This is a good practice
that improves readibility:
```{r}
# embrace braces: use them as much as possible!
x <- 10
if (x > 0) {
y <- sqrt(x)
} else {
y <- -sqrt(-x)
}
y
```
### Simple If's
There is a simplified form of if-then-else statement which is available when
there is no expression in the False part to evaluate. This statement has the general form:
```r
if (condition) expression
```
and is equivalent to:
```r
if (condition) expression else NULL
```
Here's an example:
```{r simple_if}
x <- 4
y <- 2
if (x > y) print("x is greater than y")
```
### Multiple If's
A common situation involves working with multiple conditions at the same time.
You can chain multiple if-else statements:
```{r}
y <- 1 # Change this value!
if (y > 0) {
print("positive")
} else if (y < 0) {
print("negative")
} else {
print("zero?")
}
```
#### Your turn!
Write R code that will "squish" a number into the interval [0, 100], so that a
number less than 0 is replaced by 0 and a number greater than 100 is replaced
by 100.
```{r}
z <- 100 * pi
# Fill in the following if-else statements. You may (or may not)
# have to add or subtract else if or else statements.
if (TRUE) { # Replace TRUE with a condition.
} else if (TRUE) { # Replace TRUE with a condition.
} else {
}
```
### Switch
Working with multiple chained if's becomes cumbersome. Consider the following
example that uses several if's to convert a day of the week into a number:
```{r}
# Convert the day of the week into a number.
day <- "Tuesday" # Change this value!
if (day == 'Sunday') {
num_day <- 1
} else {
if (day == "Monday") {
num_day <- 2
} else {
if (day == "Tuesday") {
num_day <- 3
} else {
if (day == "Wednesday") {
num_day <- 4
} else {
if (day == "Thursday") {
num_day <- 5
} else {
if (day == "Friday") {
num_day <- 6
} else {
if (day == "Saturday") {
num_day <- 7
}
}
}
}
}
}
}
num_day
```
Working with several nested if's like in the example above can be a nightmare.
In R, you can get rid of many of the braces like this:
```{r}
# Convert the day of the week into a number.
day <- "Tuesday" # Change this value!
if (day == 'Sunday') {
num_day <- 1
} else if (day == "Monday") {
num_day <- 2
} else if (day == "Tuesday") {
num_day <- 3
} else if (day == "Wednesday") {
num_day <- 4
} else if (day == "Thursday") {
num_day <- 5
} else if (day == "Friday") {
num_day <- 6
} else if (day == "Saturday") {
num_day <- 7
}
num_day
```
But still we have too many if's, and there's a lot of repetition in the code.
If you find yourself using many if-else statements with identical structure for
slightly different cases, you may want to consider a __switch__ statement
instead:
```{r}
# Convert the day of the week into a number.
day <- "Tuesday" # Change this value!
switch(day, # The expression to be evaluated.
Sunday = 1,
Monday = 2,
Tuesday = 3,
Wednesday = 4,
Thursday = 5,
Friday = 6,
Saturday = 7,
NA) # an (optional) default value if there are no matches
```
Switch statements can also accept integer arguments, which will act as indices
to choose a corresponding element:
```{r}
# Convert a number into a day of the week.
day_num <- 3 # Change this value!
switch(day_num,
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday")
```
### Function `stop()`
Consider the formula for the area $A$ of a circle of given radius $r$:
$$
A = \pi r^2
$$
We can write a function `circle_area()` that calculates the area of a circle.
This function takes one argument `radius`, and we can give `radius` a default
value of 1:
```{r}
circle_area <- function(radius = 1) {
pi * radius^2
}
```
For example:
```{r}
# default (radius 1)
circle_area()
# radius 3
circle_area(radius = 3)
```
What happens if you give radius a negative value?
```{r}
# default (radius 1)
circle_area(-1)
```
The function `circle_area()` still returns a value even when the radius is
negative, which does not make sense. In many cases, it is desirable to make
some checkings on the provided input. If the input is not appropriate, we
should stop the execution of the function. For this purpose, we can use the
function `stop()`
```{r, eval = FALSE}
circle_area <- function(radius = 1) {
if (radius < 0) {
stop("radius must be positive")
}
pi * radius^2
}
# this should work
circle_area(1)
# this should not work
circle_area(-1)
```