I. Ozkan, PhD 
 Professor 
 MIS 
 Cankaya
University
 
iozkan@cankaya.edu.tr
  
Fall 2025
✅ Tidyverse style guide
✅ Frequently used [some] functions
✅ Data Types in
✅ Data Creation in
❌ Control Structures in
❌ Functions in
Commonly used control structures are
if and else: testing a condition and acting on it
for: execute a loop a fixed number of times
while: execute a loop while a condition is true
repeat: execute an infinite loop (must break out of it to stop)
break: break the execution of a loop
next: skip an iteration of a loop
It is probably the most commonly used control structure in
R
It is used to test a condition and act on it depending on whether it’s true or false
Basic control-flow constructs are:
if( condition ) {
expression/do something 
}
## [1] "Five is greater than three"
## [1] "Condition is TRUE"
if( condition ) {
expression/do something 
}
## [1] "Condition is TRUE"
## [1] "Condition is TRUE"
## [1] "Condition is TRUE"
## [1] "Condition is TRUE"
## [1] "Condition is TRUE"
if( condition ) {
expression/do something 
}
## [1] "x is greater than y"
x <- 3:12 # vector
y <- 1:10 # vector 
# Recall: condition must have a length of one 
# if(x>y) print("x is greater than y")  
# Error in if (x > y) print("x is greater than y") : 
#  the condition has length > 1
x>y##  [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [1] "x has elements that are greater than elements of y"
if(sum(x>y)>0 & sum(x>y)==length(x)) { 
  print("Element-wise all elements of x are greater than elements of y")  
  
}## [1] "Element-wise all elements of x are greater than elements of y"
if (sum(x>y)) { 
  print(paste0("Element-wise x has ", sum(x>y), " elements that are greater than elements of y")) 
  
}## [1] "Element-wise x has 10 elements that are greater than elements of y"
if( condition ) {
do something 
} else {
do something different 
}
set.seed(123)
x <- sample(-10:10, 6) # 6 random numbers
y <- sample(-10:10, 6) # 6 random numbers
x>y## [1]  TRUE  TRUE FALSE FALSE  TRUE FALSE
if(sum(x>y)>0) print("x has elements that are greater than elements of y") else print("x has no element that is greater than elements of y")## [1] "x has elements that are greater than elements of y"
if (sum(x>y)) {
  
  print(paste0("x has ", sum(x>y), " elements that are greater than elements of y")) 
} else { 
    
  print("x has no element that is greater than elements of y")
  
} ## [1] "x has 3 elements that are greater than elements of y"
ifelse(condition,expression if TRUE,expression if FALSE)
## [1] "Five is greater than three"
##  [1] 2.449490 2.236068 2.000000 1.732051 1.414214 1.000000 0.000000      NaN
##  [9]      NaN      NaN      NaN
##  [1] 2.449490 2.236068 2.000000 1.732051 1.414214 1.000000 0.000000       NA
##  [9]       NA       NA       NA
##  [1]  1  2  3  4  5  6  7  8  9 10
##  [1] "1"   "2"   "3"   "4"   "XXX" "6"   "7"   "8"   "9"   "XXX"
##  [1] "odd"  "even" "odd"  "even" "odd"  "even" "odd"  "even" "odd"  "even"
ifelse(condition,expression if TRUE,expression if FALSE)
data(iris)
# create a new column containing "Large" and "Small"
iris$new.colum <- iris$Sepal.Length * iris$Sepal.Width
head(iris,3)##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species new.colum
## 1          5.1         3.5          1.4         0.2  setosa     17.85
## 2          4.9         3.0          1.4         0.2  setosa     14.70
## 3          4.7         3.2          1.3         0.2  setosa     15.04
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species new.colum
## 1          5.1         3.5          1.4         0.2  setosa     Large
## 2          4.9         3.0          1.4         0.2  setosa     Small
## 3          4.7         3.2          1.3         0.2  setosa     Small
if( condition ) {
do something 
} else if(
condition2 ) { 
 do something
different 
} else if( condition3
) { 
 do something different
} else {
 do something
different 
}
result <- 65
if (result > 90) {
  "A"
} else if (result > 80) {
    "B"
} else if (result > 50) {
    "C"
} else {
  "F"
}## [1] "C"
switch(expression,list of values)
Closely related to if
It is also possible to use switch() with a numeric
x, but is harder to read
It is recommended using switch() only with character
inputs
x <- "c"
if (x == "a") {
  "option 1"
} else if (x == "b") {
  "option 2" 
} else if (x == "c") {
  "option 3"
} else {
  stop("Invalid `x` value")
}## [1] "option 3"
## [1] "option 3"
NULL## NULL
x <- "horse"
switch(x,
    cow = ,
    horse = ,
    dog = 4,
    human = ,
    chicken = 2,
    plant = 0,
    stop("Unknown input")
)## [1] 4
## [1] "bb"
## [1] "cc"
# example from https://www.geeksforgeeks.org/switch-case-in-r/
val1 = 6
val2 = 7
val3 = "s"
switch(
    val3,
    "a"= cat("Addition =", val1 + val2),
    "d"= cat("Subtraction =", val1 - val2),
    "r"= cat("Division = ", val1 / val2),
    "s"= cat("Multiplication =", val1 * val2),
    "m"= cat("Modulus =", val1 %% val2),
    "p"= cat("Power =", val1 ^ val2),
        stop("Unknown input")
)## Multiplication = 42
# or 
switch(
    val3,
    "a"= cat("Addition =", val1 + val2),
    "d"= cat("Subtraction =", val1 - val2),
    "r"= cat("Division = ", val1 / val2),
    "s"= cat("Multiplication =", a <- val1 * val2),
    "m"= cat("Modulus =", val1 %% val2),
    "p"= cat("Power =", val1 ^ val2),
        stop("Unknown input")
)## Multiplication = 42
## [1] 42
For loops are the only looping construct that is used very frequently R
for loops are used to iterate over items in a
vector
for(item
in vector) { 
perform_action 
}
## 12345
## This is iteration i = 1 
## This is iteration i = 2 
## This is iteration i = 3 
## This is iteration i = 4 
## This is iteration i = 5
for(item
in vector) { 
perform_action 
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 1
## [1] 1 2
## [1] 1 2 3
## [1] 1 2 3 4
## [1] 1 2 3 4 5
for(item
in vector) { 
perform_action 
}
## NULL
## NULL
## [1] 7
## [1] 9
## [1] 11
## NULL
## 2: 4 8
## 5: 25 125
## 10: 100 1000
## 20: 400 8000
## 50: 2500 125000
for(item
in vector) { 
perform_action 
}
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
## [20] "t" "u" "v" "w" "x" "y" "z"
## [1] 26
# modulo operator, see ?`%%`
for (i in 1:length(letters)){
  if((i %% 4)==0) cat(i,": ",letters[i], "\n", sep = "")
}## 4: d
## 8: h
## 12: l
## 16: p
## 20: t
## 24: x
for(item
in vector) { 
perform_action 
}
nms <- c("Ayse", "Huseyin", "Serdar", "Hatice", "Safinaz") 
for(i in nms) {   
  print(paste("The name", i, "has", nchar(i), "characters"))
}## [1] "The name Ayse has 4 characters"
## [1] "The name Huseyin has 7 characters"
## [1] "The name Serdar has 6 characters"
## [1] "The name Hatice has 6 characters"
## [1] "The name Safinaz has 7 characters"
for(item
in vector) { 
perform_action 
}
# results in vectors 
x <- c()
for (i in 1:7){
  x <- rbind(x, c(i,i^2)) # rbind: combine R objects by rows 
}
x # 2 dimensional ##      [,1] [,2]
## [1,]    1    1
## [2,]    2    4
## [3,]    3    9
## [4,]    4   16
## [5,]    5   25
## [6,]    6   36
## [7,]    7   49
for(item
in vector) { 
perform_action 
}
# nested loop 
for(i in 1:2) { # first loop, 
  for(j in 1:3) { # second loop inside
    cat("This is iteration i =", i, "and j =", j,"\n") 
  } # end of second loop
} # end of first loop## This is iteration i = 1 and j = 1 
## This is iteration i = 1 and j = 2 
## This is iteration i = 1 and j = 3 
## This is iteration i = 2 and j = 1 
## This is iteration i = 2 and j = 2 
## This is iteration i = 2 and j = 3
x <- c()
for(i in 1:5) { # first loop, 
  for(j in 1:3) { # second loop inside
    x <- c(x, paste(LETTERS[i], j, sep = "_"))  # Code block
  } # end of second loop
} # end of first loop
x##  [1] "A_1" "A_2" "A_3" "B_1" "B_2" "B_3" "C_1" "C_2" "C_3" "D_1" "D_2" "D_3"
## [13] "E_1" "E_2" "E_3"
for(item
in vector) { 
perform_action 
}
# break a loop if i > 4 break  
for (i in 1:10){
  if(i<5) cat(i,": ",i^2, "\n", sep = "") else {
    cat(i,": ", "break \n", sep = "")
    break
  }
}## 1: 1
## 2: 4
## 3: 9
## 4: 16
## 5: break
# conditional skip  
for(i in 1:10) {
  if(i %in% c(1, 5, 7)) { # do not execute for these numbers 
    next
  }
  cat(i,": ",i^2, "\n", sep = "")  
}## 2: 4
## 3: 9
## 4: 16
## 6: 36
## 8: 64
## 9: 81
## 10: 100
while(condition){
 perform_action 
 }
for loops are useful the set of values for the
iteration are in advance. If not, there are two related tools with more
flexible specifications:
while(condition) action: performs action while
condition is TRUE.
repeat(action): repeats action forever
(i.e. until it encounters break).
## x:  6    1:x-> 1 2 3 4 5 6 
## x:  7    1:x-> 1 2 3 4 5 6 7 
## x:  8    1:x-> 1 2 3 4 5 6 7 8 
## x:  9    1:x-> 1 2 3 4 5 6 7 8 9 
## x:  10    1:x-> 1 2 3 4 5 6 7 8 9 10
while(condition){
 perform_action 
 }
## x:  5 
## x:  6 
## x:  7
while(condition){
 perform_action 
 }
# nested loop for in while
i <- 2
while(i <= 3) {
  for(j in 1:4) {
    print(paste("This is iteration i =", i, "and j =", j))
  }
  i <- i + 1
}## [1] "This is iteration i = 2 and j = 1"
## [1] "This is iteration i = 2 and j = 2"
## [1] "This is iteration i = 2 and j = 3"
## [1] "This is iteration i = 2 and j = 4"
## [1] "This is iteration i = 3 and j = 1"
## [1] "This is iteration i = 3 and j = 2"
## [1] "This is iteration i = 3 and j = 3"
## [1] "This is iteration i = 3 and j = 4"
# nested loop while in while
i <- 2
while(i <= 3) {
  j <- 1
  while(j <= 3) {
    print(paste("This is iteration i =", i, "and j =", j))
    j <- j + 1
  }
  i <- i + 1
}## [1] "This is iteration i = 2 and j = 1"
## [1] "This is iteration i = 2 and j = 2"
## [1] "This is iteration i = 2 and j = 3"
## [1] "This is iteration i = 3 and j = 1"
## [1] "This is iteration i = 3 and j = 2"
## [1] "This is iteration i = 3 and j = 3"
while(condition){
 perform_action 
 }
nms <- c("Ayse", "Huseyin", "Serdar", "Hatice", "Safinaz") 
i <- 1
while(i<=length(nms)) {   
  print(paste("The name", nms[i], "has", nchar(nms[i]), "characters"))
  i <- i + 1
}## [1] "The name Ayse has 4 characters"
## [1] "The name Huseyin has 7 characters"
## [1] "The name Serdar has 6 characters"
## [1] "The name Hatice has 6 characters"
## [1] "The name Safinaz has 7 characters"
while(condition){
 perform_action 
 }
nms <- c("Ayse", "Huseyin", "Serdar", "Hatice", "Safinaz") 
# a bit complex one, extract all characters from string using
# stringr package function, see ?str_match_all, and regex 
i <- 1
while(i<=length(nms)) {   
  print(paste(nms[i], "has", nchar(nms[i]), "characters","and",length(unique(str_match_all(nms[i], "(?<=(\\w{1}))")[[1]][,2])),"unique characters:",paste(unique(str_match_all(nms[i], "(?<=(\\w{1}))")[[1]][,2]),collapse=", ")))
    i <- i + 1
}## [1] "Ayse has 4 characters and 4 unique characters: A, y, s, e"
## [1] "Huseyin has 7 characters and 7 unique characters: H, u, s, e, y, i, n"
## [1] "Serdar has 6 characters and 5 unique characters: S, e, r, d, a"
## [1] "Hatice has 6 characters and 6 unique characters: H, a, t, i, c, e"
## [1] "Safinaz has 7 characters and 6 unique characters: S, a, f, i, n, z"
repeat{ 
perform_action 
 until break }
## [1] 4
## x:  4    1:x-> 1 2 3 4 
## x:  5    1:x-> 1 2 3 4 5 
## x:  6    1:x-> 1 2 3 4 5 6 
## x:  7    1:x-> 1 2 3 4 5 6 7
repeat{ 
perform_action 
 until break }
## [1] 6
## x:  6 
## x:  7 
## x:  8 
## x:  9
repeat{ 
perform_action 
 until break }
# nested loop for in repeat
i <- 2
repeat{
  for(j in 1:3) {
    print(paste("This is iteration i =", i, "and j =", j))
  }
  i <- i + 1
  if(i > 3) break 
}## [1] "This is iteration i = 2 and j = 1"
## [1] "This is iteration i = 2 and j = 2"
## [1] "This is iteration i = 2 and j = 3"
## [1] "This is iteration i = 3 and j = 1"
## [1] "This is iteration i = 3 and j = 2"
## [1] "This is iteration i = 3 and j = 3"
repeat{ 
perform_action 
 until break }
# nested loop repeat in while
i <- 2
while(i <= 3) {
  j <- 1
  repeat{
    print(paste("This is iteration i =", i, "and j =", j))
    j <- j + 1
    if(j > 5) break
  }
  i <- i + 1
}## [1] "This is iteration i = 2 and j = 1"
## [1] "This is iteration i = 2 and j = 2"
## [1] "This is iteration i = 2 and j = 3"
## [1] "This is iteration i = 2 and j = 4"
## [1] "This is iteration i = 2 and j = 5"
## [1] "This is iteration i = 3 and j = 1"
## [1] "This is iteration i = 3 and j = 2"
## [1] "This is iteration i = 3 and j = 3"
## [1] "This is iteration i = 3 and j = 4"
## [1] "This is iteration i = 3 and j = 5"
repeat{ 
perform_action 
 until break }
# nested loop repeat in repeat
i <- 2
repeat{
  j <- 1
  repeat{
    print(paste("This is iteration i =", i, "and j =", j))
    j <- j + 1
    if(j > 5) break
  }
  i <- i + 1
  if(i > 3) break 
}## [1] "This is iteration i = 2 and j = 1"
## [1] "This is iteration i = 2 and j = 2"
## [1] "This is iteration i = 2 and j = 3"
## [1] "This is iteration i = 2 and j = 4"
## [1] "This is iteration i = 2 and j = 5"
## [1] "This is iteration i = 3 and j = 1"
## [1] "This is iteration i = 3 and j = 2"
## [1] "This is iteration i = 3 and j = 3"
## [1] "This is iteration i = 3 and j = 4"
## [1] "This is iteration i = 3 and j = 5"
repeat{ 
perform_action 
 until break }
nms <- c("Ayse", "Huseyin", "Serdar", "Hatice", "Safinaz") 
i <- 1
repeat{   
  print(paste("The name", nms[i], "has", nchar(nms[i]), "characters"))
  i <- i + 1
  if (i > length(nms)) break 
}## [1] "The name Ayse has 4 characters"
## [1] "The name Huseyin has 7 characters"
## [1] "The name Serdar has 6 characters"
## [1] "The name Hatice has 6 characters"
## [1] "The name Safinaz has 7 characters"
repeat{ 
perform_action 
 until break }
nms <- c("Ayse", "Huseyin", "Serdar", "Hatice", "Safinaz") 
# a bit complex one, extract all characters from string using
# stringr package function, see ?str_match_all, and regex 
i <- 1
repeat{   
  print(paste(nms[i], "has", nchar(nms[i]), "characters","and",length(unique(str_match_all(nms[i], "(?<=(\\w{1}))")[[1]][,2])),"unique characters:",paste(unique(str_match_all(nms[i], "(?<=(\\w{1}))")[[1]][,2]),collapse=", ")))
  i <- i + 1
  if (i > length(nms)) break 
}## [1] "Ayse has 4 characters and 4 unique characters: A, y, s, e"
## [1] "Huseyin has 7 characters and 7 unique characters: H, u, s, e, y, i, n"
## [1] "Serdar has 6 characters and 5 unique characters: S, e, r, d, a"
## [1] "Hatice has 6 characters and 6 unique characters: H, a, t, i, c, e"
## [1] "Safinaz has 7 characters and 6 unique characters: S, a, f, i, n, z"
repeat{ 
perform_action 
 until break }
You can rewrite any for loop to use
while instead
You can rewrite any while loop to use
repeat
while is more flexible than for, and
repeat is more flexible than while
It’s good practice, to use the least-flexible solution to
a problem, so you should use for wherever
possible
Writing functions is a core activity of an R programmer
If the same block of code is used frequently, perhaps under slightly different conditions, then consider writing a function
Functions make the code easier to read
Functions can be re-usable with different data, parameter values etc.
Functions can be passed as arguments to other functions
Functions can be nested, so that you can define a function inside of another function
formals() functionExample: formals(sd)
$x
$na.rm
[1] FALSE
body() functionExample: body(sd)
sqrt(var(if (is.vector(x) || is.factor(x)) x else as.double(x), 
    na.rm = na.rm))
environment()
functionExample: environment(sd)
<environment: namespace:stats>
Name of Function
Consider proper name that is understandable
Arguments of Function
Data, values for some parameters are passed through the body code using arguments
Function returns
Either plot, data, values
etc., are returned. return() function is frequently
used.
function_name <- function(argument_1, argument_2, argument_3,...){
  
           function_task/Body
  
           return(output)
}
# Good
add_row()
permute()
# Bad
row_adder()
permutation()
long_function_name <- function(a = "a long argument",
                               b = "another argument",
                               c = "another long argument") {
  # As usual code is indented by two spaces.
}
or
long_function_name <- function(
    a = "a long argument",
    b = "another argument",
    c = "another long argument") {
  # As usual code is indented by two spaces.
}
return() function should be used for early return. The last evaluated expression automatically returned otherwise
# Good
find_abs <- function(x) {
  if (x > 0) {
    return(x)
  }
  x * -1
}
add_two <- function(x, y) {
  x + y
}
# Bad
add_two <- function(x, y) {
  return(x + y)
}
find_abs <- function(x) {
  if (x > 0) return(x)
  x * -1
}
f <- function() { # function name = f, class = function
  
  # Empty Function No Task, return nothing: NULL
  
}
f()## NULL
## [1] "function"
## NULL
# Argument without default 
f <- function(person) {
  
  cat("Hello ", person, "!\n")
  
}
# f()
# Error in f() : argument "person" is missing, with no default
f("Ali")## Hello  Ali !
## Hello  Ali !
R functions arguments can be matched positionally or by
name
Positional matching just means that R assigns the first value to the first argument, the second value to second argument, etc.
The order of matching:
# Argument with default 
f <- function(person = "Ali", age = 22) {
  
  cat("Hello ", person, ". You are", age, "years old \n")
  
}
f()## Hello  Ali . You are 22 years old
## Hello  Veli . You are 22 years old
## Hello  Veli . You are 22 years old
## Hello  Veli . You are 29 years old
## Hello  Veli . You are 29 years old
## Hello  Veli . You are 29 years old
## Hello  Ece . You are 23 years old
mean(), a built-in R
function to compute mean of a numeric vectorCheck the function’s help page with ?mean
Let’s take 2 minutes to investigate the help page for
meanin R Studio or Click to Read Online
trim do?## [1] 100
## [1]  1  4  9 16 25
## [1] 0
## [1] 100
## [1]  1  4  9 16 25
# using, other functions utils function tail() and base
# function, cumprod() 
my_factorial2 <- function(n=1) {
  if (n == 0) {
    return(1)
  } else {
    if(n < 0) {
      return(NaN)
    }
    tail(cumprod(1:n),1)
  }
}
my_factorial2(-2)## [1] NaN
## [1] 1
## [1] 2
## [1] 120
# using, utils function tail() and base function, cumprod(): ? 
my_factorial2 <- function(n=1) {
  if (n == 0) {
    return(1)
  } else {
    if(n < 0) {
      return(NaN)
    }
    tail(cumprod(1:n),1)
  }
}
my_factorial2(-2)## [1] NaN
## [1] 1
## [1] 2
## [1] 120
Some SWs use eaer evaluation where all the arguments to a function is evaluated before the body of the function is evaluated
In lazy evaluation, arguments become promise and evaluated when it is called
## [1] 4
# using eval(), substitute() functions
# ?eval and ?substitute for help 
my_function <- function(my_expression, x) {
  eval(substitute(my_expression))
}
my_function(my_expression = x^2-1, x = 3)## [1] 8
## [1] -1
## [1] 8
## [1]  0  3  8 15 24
## [1] 3.0 3.5 4.0 4.5 5.0
my_curve <- function(my_expression, from, to) {
  x <- seq(from=from, to=to, length.out=100)
  y <- eval(substitute(my_expression)) 
  plot(x,y, type = "l")
}
my_curve(x^2-1,from=-2, to=2)# Plotting function using plot() and seq() function 
my_curve <- function(my_expression, from, to) {
  x <- seq(from=from, to=to, length.out=100)
  y <- eval(substitute(my_expression)) 
  plot(x,y, type = "l")
}
my_curve(-2*x^2 + 3*x -1,from=-2, to=2)my_curve2 <- function(my_expression, from, to) {
  if (missing(from)){
    print("Arguemnt `from` is missing") 
    return(NULL)
  } 
  if (missing(to)){
    print("Arguemnt `to` is missing") 
    return(NULL)
  } 
  x <- seq(from=from, to=to, length.out=100)
  y <- eval(substitute(my_expression)) 
  plot(x,y, type = "l")
}
my_curve2(-2*x^2 + 3*x -1,from=-2, to=2) ## [1] "Arguemnt `from` is missing"
## NULL
## [1] "Arguemnt `to` is missing"
## NULL
# defaults: from = 2, to = 2
my_curve3 <- function(my_expression, from=-2, to=2) {
  x <- seq(from=from, to=to, length.out=100)
  y <- eval(substitute(my_expression)) 
  plot(x,y, type = "l")
}
par(mfrow = c(2,2)) # 4 plotting window, 2x2
my_curve3(-2*x^2 + 3*x -1) 
my_curve3(-2*x^2 + 3*x -1, to=4) 
my_curve3(-2*x^2 + 3*x -1, from=-4)
my_curve3(-2*x^2 + 3*x -1, from = -4, to = 4)Do not use assignment operator for arguments
Always use comments (#) to explain why