rm (list=ls())#################################################################################################################################### Intro to for loop. #### The for loop is similar to the while loop in that it causes a ## body of code to be repeated more than once. However, the for## loop is DIFFERENT from the while loop in how it accomplishes ## the repetition.#### It's probably easiest to understand how the for loop works## if you examine the example code that appears below. However,## the following is an attempt to explain in words how the for ## loop works. I recommend that you look at the examples below## and then come back and read this more detailed explanation.#### ------------------------------------------------------------#### Code of "for loops" is arranged in the following format.#### for ( SOME_VARIABLE in SOME_VECTOR__OR__SOME_LIST ){#### # statements that#### # may refer to #### # the variable#### }#### NOTES:#### 1. SOME_VARIABLE is the name of a variable. This variable is created just for## the purpose of the for loop. You cannot refer to this variable outside## of the code for the for loop. (If the same name is used for a variable## outside of the for loop it is a different variable).#### 2. SOME_VECTOR__OR__SOME_LIST is a vector or a list.## This could be a variable name that was created before the## for loop started or it could be the result a function that creates## a vector or a list.#### 3. The code executes in the following way:#### step 1. The first value in the vector (or list) is assigned to the variable.#### step 2. The body of the loop (i.e. code between {curly braces}) is executed.## [The code in the body may refer to the variable but it doesn't have to.]#### step 3. After the {body} finishes executing once, the next value from the## vector (or list) is assigned to the variable.#### step 4. The body of the for loop is then executed again. ## However, this time the value of the variable is the 2nd value## from the vector (or list).#### step 5. The for loop keeps replacing the value of the variable with the ## next value from the vector (or list) and then doing the code in ## the {body} until it runs out of values from the vector (or list).#### step 6. After all values from the vector (or list) have been processed,## the loop is finished and execution continues with the line after## the end of the body of the loop - i.e. the line after the "}"################################################################################################################################### This file goes through several examples of using a for loop and a while loop.# Be sure to see the notes at the bottom of this file for some important# concepts and a discussion of when a for loop is an option and when# you must use a while loop.#-----------------------------# Example of a for loop## Everything you need to know about a for loop is in the first line of the # loop (i.e. the line that starts with the word "for").# In the following example, the first line says: for(num in 10:1).## In this example, num is the variable and 10:1 is the vector, i.e. c(10,9,8,7,6,5,4,3,2,1)# # The 1st value from the vector (i.e. 10) is assigned to the variable, num# Then the body of the loop is executed. # # The 2nd value from the vector (i.e. 9) is assigned to the variable, num# Then the body of the loop is executed. # # The 3rd value from the vector (i.e. 8) is assigned to the variable, num# Then the body of the loop is executed. ## etc ...## After all the values from the vector have been processed, the loop is finished.#-----------------------------countdown <-function (){for (num in10:1){ # each time through the loop another value from 10:1 is assigned to numcat(num," ") # display num followed by a spaceSys.sleep(2.5) # sleep for 0.25 seconds }cat("blastoff!") # after the loop has finished, display "blastoff!"}countdown()
10 9 8 7 6 5 4 3 2 1 blastoff!
#----------------------------------------------------------------------# A for loop can always be rewritten as a while loop.# The following rewrites the above example to use a while loop.#----------------------------------------------------------------------countdownWithWhile <-function (){ num =10# setup the variables to be used in the condition of the whilewhile(num >=1){ # condition that's TRUE when loop should run and FALSE when loop should endcat(num, " ")Sys.sleep(0.25) num <- num -1# change some variable that is part of the condition } # END OF WHILE - code below will only happen after while finishescat("blastoff!") }countdownWithWhile()
10 9 8 7 6 5 4 3 2 1 blastoff!
#----------------------------------------------------------------------# A "for loop" can use ANY vector or list## Other examples of vectors# - character and logical vectors# - numeric vectors that don't count by ones#----------------------------------------------------------------------#-----------------------------------# Count by two's - with a for loop#-----------------------------------countByTwos_for =function(){ vec =seq(2,10, by=2)for ( num in vec){cat("I like number", num, "\n") }}countByTwos_for()
I like number 2
I like number 4
I like number 6
I like number 8
I like number 10
# rewriting the same example with a while loopcountByTwos_while =function(){ num =2while ( num <=10){cat("I like number", num, "\n") num = num +2 }}countByTwos_while()
I like number 2
I like number 4
I like number 6
I like number 8
I like number 10
#-----------------------------------------------------------------------.# Any code with a "for loop" can be converted to equivalent code# with a while loop by following these steps:## step 1: before the while loop copy the vector (or list) # from the for loop in to a new variable, eg. vecOrList## step 2: create a variable for the position in the vector (or list)# to be processed at each iteration through the body of the loop## step 3: write the while loop with the condition# while ( position <= length(vecOrList) )## while ( position <= length(vecOrList) )## We demonstrate this by following these steps to rewrite# the code from the countByTwos_for function to an equivalent# function with a while loop.#-----------------------------------------------------------------------.# Rewrite the for countByTwos function to use a while loop in a way that# we can apply the same approach to convert ANY for loop into an# equivalent while loopcountByTwos_for =function(){# step 1: copy the vector from the for loop in to a variable vec =seq(2,10, by=2) # step 2: create a variable for the position in the vector (or list)# to be processed at each iteration through the body of the loop position =1while ( position <=length(vec)){ # step 3: write the condition for the whilecat("I like number", vec[position], "\n")# step 4: at the end of the body of the loop add one to the position# variable position = position +1 }}debugonce(countByTwos_for)countByTwos_for()
debugging in: countByTwos_for()
debug at <text>#184: {
vec = seq(2, 10, by = 2)
position = 1
while (position <= length(vec)) {
cat("I like number", vec[position], "\n")
position = position + 1
}
}
debug at <text>#187: vec = seq(2, 10, by = 2)
debug at <text>#191: position = 1
debug at <text>#193: while (position <= length(vec)) {
cat("I like number", vec[position], "\n")
position = position + 1
}
debug at <text>#195: cat("I like number", vec[position], "\n")
I like number 2
debug at <text>#199: position = position + 1
debug at <text>#193: (while) position <= length(vec)
debug at <text>#195: cat("I like number", vec[position], "\n")
I like number 4
debug at <text>#199: position = position + 1
debug at <text>#193: (while) position <= length(vec)
debug at <text>#195: cat("I like number", vec[position], "\n")
I like number 6
debug at <text>#199: position = position + 1
debug at <text>#193: (while) position <= length(vec)
debug at <text>#195: cat("I like number", vec[position], "\n")
I like number 8
debug at <text>#199: position = position + 1
debug at <text>#193: (while) position <= length(vec)
debug at <text>#195: cat("I like number", vec[position], "\n")
I like number 10
debug at <text>#199: position = position + 1
debug at <text>#193: (while) position <= length(vec)
exiting from: countByTwos_for()
##################################################################.# QUESTION##################################################################.# # Write a function that takes a matrix, m, as an argument. # The function should return a new matrix that# # multiplies the 1st row by 10# multiplies the 2nd row by 100# multiplies the 3rd row by 1000# etc ... for all rows of the matrix## (a) - Write the function using a for loop# (b) - Write the function using a while loop###################################################################.# ANSWER - for loopmultRows_for =function ( m ) { multiplier =10for(row in1:nrow(m) ){ m[row,] = m[row,] * multiplier multiplier = multiplier *10 }return(m)}multRows_for(m)
Error in eval(expr, envir, enclos): object 'm' not found
# Test the answer:## Here is some data to start you off. The code should work # will all possible matrices. Here are some to start you off in # testing your work. m =matrix(seq(1, 18, 1) , nrow=3, ncol=6)m
##################################################################.# QUESTION##################################################################.# # Write a function that takes a matrix, m, as an argument. # The function should return a new matrix that# # adds 2 (i.e. 1+1) the value in position 1,1 # adds 3 (i.e. 1+2) the value in position 1,2 # adds 4 (i.e. 1+3) the value in position 1,3 # ... and similarly for the rest of the values in row 1## adds 3 (i.e. 2+1) the value in position 2,1 # adds 4 (i.e. 2+2) the value in position 2,2 # adds 5 (i.e.2+3) the value in position 2,3 # ... and similarly for the rest of the values in row 2## etc ... for all rows in the matrix## Use nested loops for your answer## (a) - Write the function using nested for loops# (b) - Write the function using nested while loops# (c) - Write the function using nested loops, one should be a for loop# and one a while loop (your choice which is which)###################################################################.# Answer - forchangeRows_for =function( m ){for( row in1:nrow(m)){for (col in1:ncol(m)){ m[row, col] = m[row,col] + row + col } }return(m)}# Test the functionm =matrix( 0 , nrow=3, ncol=6)m
#----------------------------------------------------# ANOTHER EXAMPLE: display character values in a vector#----------------------------------------------------#.................# With a for loop#.................anotherExample_for =function( foods ){cat("Hello. \n")for (item in foods) {cat(item, "is yummy.\n")cat("Everyone likes", item, ".\n")cat("I hope we have", item, "for supper!\n\n") }cat("bye bye.\n")}anotherExample_for (c("pizza", "french fries", "burger", "chicken", "ice cream"))
Hello.
pizza is yummy.
Everyone likes pizza .
I hope we have pizza for supper!
french fries is yummy.
Everyone likes french fries .
I hope we have french fries for supper!
burger is yummy.
Everyone likes burger .
I hope we have burger for supper!
chicken is yummy.
Everyone likes chicken .
I hope we have chicken for supper!
ice cream is yummy.
Everyone likes ice cream .
I hope we have ice cream for supper!
bye bye.
Hello.
cake is yummy.
Everyone likes cake .
I hope we have cake for supper!
lasanga is yummy.
Everyone likes lasanga .
I hope we have lasanga for supper!
chullent is yummy.
Everyone likes chullent .
I hope we have chullent for supper!
bye bye.
anotherExample_for (character(0))
Hello.
bye bye.
anotherExample_for( list("apple", "orange")) # for loops also work with lists
Hello.
apple is yummy.
Everyone likes apple .
I hope we have apple for supper!
orange is yummy.
Everyone likes orange .
I hope we have orange for supper!
bye bye.
#...................# With a while loop#...................# You can convert any for loop to a while loop.# Use the while loop to process each position in the vector (or the list).# This is what the for loop actually does for you, but we can do it ourselves.## The following shows a general way to convert ANY for loop into a while loop.# We highlighted the lines of code in this version that are different from # the previous version. All other lines of code are EXACTLY the same.anotherExample_while =function( foods ){cat("Hello. \n") position =1# new linewhile(position<=length(foods)){ # new line item = foods[[position]] # new line; [[ ]] works with both lists and vectorscat(item, "is yummy.\n")cat("Everyone likes", item, ".\n")cat("I hope we have", item, "for supper!\n\n") position = position +1# new line }cat("bye bye.\n")}# This produces the exact same results as the for loopanotherExample_while (c("pizza", "french fries", "burger", "chicken", "ice cream"))
Hello.
pizza is yummy.
Everyone likes pizza .
I hope we have pizza for supper!
french fries is yummy.
Everyone likes french fries .
I hope we have french fries for supper!
burger is yummy.
Everyone likes burger .
I hope we have burger for supper!
chicken is yummy.
Everyone likes chicken .
I hope we have chicken for supper!
ice cream is yummy.
Everyone likes ice cream .
I hope we have ice cream for supper!
bye bye.
Hello.
cake is yummy.
Everyone likes cake .
I hope we have cake for supper!
lasanga is yummy.
Everyone likes lasanga .
I hope we have lasanga for supper!
chullent is yummy.
Everyone likes chullent .
I hope we have chullent for supper!
bye bye.
Hello.
apple is yummy.
Everyone likes apple .
I hope we have apple for supper!
orange is yummy.
Everyone likes orange .
I hope we have orange for supper!
bye bye.
#######################.# QUESTION#######################.#-----------------------------------------------------------------# SOMETIMES you MUST use a while loop.#-----------------------------------------------------------------# Some problems that cannot be coded with a for loop# but rather require that you use a WHILE loop.## To use a for loop, you must be able to construct a vector that # contains all possible values that you will loop through.## However, sometimes, you don't know what those values are or how# many times you will need to process the loop.#-----------------------------------------------------------------# EXAMPLE - guessing game cannot be done with a for loop.# The loop can go on forever if the user keeps getting the wrong answer.# The following function is coded with a WHILE loop.# (you cannot write this function with a for loop)guessingGame <-function(low=1, high=10){ num <-sample(low:high, 1) numGuesses <-1 guess <-as.numeric( readline( paste0("guess a number between ", low, " and ", high, ": " )))while(guess != num) {if (guess < num){ guess <-as.numeric( readline("higher, guess again: ") ) } elseif (guess > num) { guess <-as.numeric( readline("lower, guess again: ") ) } numGuesses <- numGuesses +1 } cat("You got it in", numGuesses, "guesses.")}guessingGame()
guess a number between 1 and 10:
Error in while (guess != num) {: missing value where TRUE/FALSE needed
guessingGame()
guess a number between 1 and 10:
Error in while (guess != num) {: missing value where TRUE/FALSE needed
guessingGame()
guess a number between 1 and 10:
Error in while (guess != num) {: missing value where TRUE/FALSE needed
# EXAMPLE - firstNPrimes cannot be done with a for loop. I have # no idea how many numbers I'll have to check to find the 1000th prime# or the millionth prime. There is no simple formula that will give# that answer. Therefore, there is no way to know how long the vector # should be for the for loop.#-----------------------------------------------------------------# With a for loop you must use a variable even when there # is no need for the value.#-----------------------------------------------------------------# The following for loop does NOT make reference to the num variable# at all. However, it is still required to be specified in the code.sayHello =function( numTimes ) {for (num in1:numTimes){ name =readline("What is your name? ")cat("Hello ", name, ".\n", sep="")cat("I'm fine.\n")cat("How are you doing?\n\n") }cat("bye bye.")}sayHello(3) # say hello three times
What is your name?
Hello .
I'm fine.
How are you doing?
What is your name?
Hello .
I'm fine.
How are you doing?
What is your name?
Hello .
I'm fine.
How are you doing?
bye bye.
#-------------------------------------------------------------------------# QUESTION: Write a function: box = function(rows, cols)# to draw a box in the following pattern using nested for loops## > box (rows = 3 , cols = 4)# 3333# 2222# 1111#-------------------------------------------------------------------------box =function(rows, cols){for (rowNumber in rows:1){ # count down - we're showing row numbers in reversefor (colNumber in1:cols){ # we can count up or down - we're not using colNumbercat(rowNumber) }cat("\n") }}debugonce(box)box(3, 4)
debugging in: box(3, 4)
debug at <text>#492: {
for (rowNumber in rows:1) {
for (colNumber in 1:cols) {
cat(rowNumber)
}
cat("\n")
}
}
debug at <text>#494: for (rowNumber in rows:1) {
for (colNumber in 1:cols) {
cat(rowNumber)
}
cat("\n")
}
debug at <text>#495: for (colNumber in 1:cols) {
cat(rowNumber)
}
debug at <text>#497: cat(rowNumber)
3debug at <text>#497: cat(rowNumber)
3debug at <text>#497: cat(rowNumber)
3debug at <text>#497: cat(rowNumber)
3debug at <text>#500: cat("\n")
debug at <text>#495: for (colNumber in 1:cols) {
cat(rowNumber)
}
debug at <text>#497: cat(rowNumber)
2debug at <text>#497: cat(rowNumber)
2debug at <text>#497: cat(rowNumber)
2debug at <text>#497: cat(rowNumber)
2debug at <text>#500: cat("\n")
debug at <text>#495: for (colNumber in 1:cols) {
cat(rowNumber)
}
debug at <text>#497: cat(rowNumber)
1debug at <text>#497: cat(rowNumber)
1debug at <text>#497: cat(rowNumber)
1debug at <text>#497: cat(rowNumber)
1debug at <text>#500: cat("\n")
exiting from: box(3, 4)
box(4, 10)
4444444444
3333333333
2222222222
1111111111
#-------------------------------------------------------------------------# QUESTION - rewrite the box function from the previous question# to use nested while loops#-------------------------------------------------------------------------boxWithWhile =function( rows, cols){ rowNum = rows colNum =1while (rowNum >=1){ colNum =1while (colNum <= cols){cat(rowNum) colNum = colNum +1 }cat("\n") rowNum = rowNum -1 }}boxWithWhile(3,4)
3333
2222
1111
#-------------------------------------------------------------------------# QUESTION - Write a function## triangle = function(size)## that draws a triangle in the following pattern using nested for loops.## > triangle(3)# 1# 21# 321#-------------------------------------------------------------------------triangle =function(size){for(row in1:(size*2)){for(col in row:1){cat(col) }cat("\n") }}triangle(3)
#-------------------------------------------------------------------------# QUESTION - rewrite the triangle function from the previous question# to use nested while loops# > triangle(3)# 1# 21# 321#-------------------------------------------------------------------------triangle =function(size){ row =1while(row <= size) { col = rowwhile(col >=1) {cat(col) col = col -1 }cat("\n") row = row +1 }}triangle(3)
1
21
321
#-------------------------------------------------------------------------# QUESTION - Write a function## triangle = function(size)## that draws a triangle in the following pattern using nested for loops.## > triangle(3)# 1# 21# 321## > triangle(4)# 1# 21# 321# 4321## HINT: you can think of this "triangle" as a "box" but where some of the # spots are actually spaces. It might help to view the spaces as periods# so that you can see them. Think about how to draw each of the rows - # you can split up each row into (a) drawing the periods and (b) drawing the # numbers## > triangle(3)# ..1# .21# 321## > triangle(4)# ...1# ..21# .321# 4321#-------------------------------------------------------------------------triangle =function(size){# FILL IN THE CODE}###########################################################################.# 2022 - WILF - UP TO HERE - AFTER CLASS 26###########################################################################.############################################################################.# & vs &&# | vs ||## There are two type of "and" operators and two types of "or" operators# in R. # The 1st type is & and |. ## The 2nd type is && and || (with doubled symbols).## It is preferable to use the "doubled" operators for# conditions in both "if statements" and in "while loops". # The reason is based on the following two fundamental differences between the# single symbol operators & and | vs the double symbols operators && and ||### *** FIRST DIFFERENCE ***## & and | are "vectorized operators" while && and || are not vectorized## The single & and | are vectorized (i.e. they will return an entire # vector of multiple TRUE/FALSE values if necessary). In the following# example, there are two values in the answer## > c(TRUE, TRUE) & c(FALSE, TRUE)# [1] FALSE TRUE## By contrast, the double && and || operators only return # the first TRUE or FALSE## > c(TRUE, TRUE) && c(FALSE, TRUE)# [1] FALSE ### *** SECOND DIFFERENCE *** # && and || are "shortcut operators", & and | are not.## The double && and || will only process the values up until an answer# can be figured out. We call these shortcut operators.## By contrast, the single & and | will process ALL values## See examples below.##########################################################################.#------------------------------.# Examples for difference #1 #------------------------------.# & and | return multiple TRUE/FALSE values # (i.e. & and | are "vectorized" operators)c(TRUE,TRUE,TRUE) |c(FALSE, TRUE, FALSE)
[1] TRUE TRUE TRUE
c(TRUE,TRUE,TRUE) &c(FALSE, TRUE, FALSE)
[1] FALSE TRUE FALSE
# The double operators only return the first value for the answer.## This is what you want for the conditions in "if statements" and# in "while loops" since the entire condition should evaluate# to a single TRUE or FALSEc(TRUE,TRUE,TRUE) ||c(FALSE, TRUE, FALSE)
Error in c(TRUE, TRUE, TRUE) || c(FALSE, TRUE, FALSE): 'length = 3' in coercion to 'logical(1)'
c(TRUE,TRUE,TRUE) &&c(FALSE, TRUE, FALSE)
Error in c(TRUE, TRUE, TRUE) && c(FALSE, TRUE, FALSE): 'length = 3' in coercion to 'logical(1)'
#------------------------------.# Examples for difference #2#------------------------------.# && and || use "shortcut" logic:## FALSE && ANYTHING # The answer MUST BE FALSE## TRUE && ______ # I don't konw the answer until I analyze the ______##### TRUE || ANYTHING # The answer MUST BE TRUE## FALSE || ______ # I don't konw the answer until I analyze the ______# In the following code, the trunc will not be processed if# is.numeric is FALSE. This is appropriate since trunc would fail # with an error if it is passed a character value.isWholeNumber =function( x ){ tf =is.numeric(x) &&trunc(x) == x return (tf)}isWholeNumber(3.5) # FALSE
[1] FALSE
isWholeNumber(3) # TRUE
[1] TRUE
isWholeNumber(-3) # TRUE
[1] TRUE
isWholeNumber(-3.5) # TRUE
[1] FALSE
isWholeNumber("apple") # FALSE (this is correct)
[1] FALSE
# The following code incorrectly uses & # Therefore the code fails with an error when passed a# character value.isWholeNumber_bad =function( x ){ tf =is.numeric(x) &trunc(x) == x return (tf)}isWholeNumber_bad(3.5) # FALSE
[1] FALSE
isWholeNumber_bad(3) # TRUE
[1] TRUE
isWholeNumber_bad("apple") # ERROR - non-numeric argument to trunc
Error in trunc(x): non-numeric argument to mathematical function
# In general when using && and || in conditions for "if statements"# and "while loops", use the double version (i.e. && and || # instead of & and |)is.prime <-function( num ) {# DON'T DO THE FOLLOWING:## if( !is.numeric(num) | trunc(num) != num | num < 1 ){# RATHER, DO THE FOLLOWING:if( length(num) !=1||!is.numeric(num) ||trunc(num) != num || num <1 ){stop("num must be a single positive whole number") }if (num <2){return(FALSE) } divisor <-2while ( divisor <=sqrt(num) ) {if (num %% divisor ==0){return(FALSE) } divisor <- divisor +1 }return(TRUE)}is.prime("apple")
Error in is.prime("apple"): num must be a single positive whole number
is.prime(c(100,200,300))
Error in is.prime(c(100, 200, 300)): num must be a single positive whole number
#-------------------------------------------------------------------#-------------------------------------------------------------------# The following is a slight digression to discuss return values ...## STUDENTS who are new to R are often confused about these ideas ...#-------------------------------------------------------------------#-------------------------------------------------------------------#..................................................................# *** TL;DR *** (i.e. the main idea) ...# (keep reading the comments below for a more lengthy explanation): #..................................................................## The countdown function does NOT return the numbers# nor the word "blastoff!". Rather the return value of countdown() is the # value of cat("blastoff!") function, which is invisible, and is NULL.# Same code as abovecountdown <-function (){for (num in10:1){ # each time through the loop another value from 10:1 is assigned to numcat(num," ") # display num followed by a spaceSys.sleep(0.25) # sleep for 0.25 seconds }cat("blastoff!") # after the loop has finished, display "blastoff!"}countdown() # 10 9 8 7 6 5 4 3 2 1 blastoff!
10 9 8 7 6 5 4 3 2 1 blastoff!
x <-countdown()
10 9 8 7 6 5 4 3 2 1 blastoff!
x # NULL
NULL
#..................................................................# *** A SOMEWHAT MORE LENGTHY EXPLANATION OF THESE CONCEPTS ***#..................................................................# First of all, remember that if a function doesn't execute an explicit# return statement, then the value of the final command to be executed is returned# from the function.## Therefore, in the case of the countdown function above, what is "returned" is the # value of cat("blastoff!") ... (but this is NOT the word "blastoff!" ... keep reading).# The return value of cat is always NULL.# In the next line the return value is NULL, NOT "hello". # The return value, NULL, is then assigned to the variable x.# Even though the word "hello" is NOT the return value,# nevertheless, the word hello (without quotes) is displayed because cat # will always display info to the screen.x <-cat("hello") # displays hello (without quotes) to the screen
hello
x # NULL
NULL
# One more example ...# Remember, the rep function repeats the VALUE of the first argument.rep("hello", 5) # "hello" "hello" "hello" "hello" "hello"
[1] "hello" "hello" "hello" "hello" "hello"
rep(seq(1,3), 5) # 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
[1] 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
# In the following example, the return value of cat is NULL.# However, NULL is NOT repeated 5 times, only once.# This is due to the special nature of the value NULL (which basically# means "nothing"). NULL is special in that even 5 NULLs are displayed# as a single NULL - don't worry too much about the intricacies of NULL,# but you must know that the return value of cat is NOT "hello".rep(cat("hello"), 5) # helloNULL
hello
NULL
rep(NULL, 5) # NULL (only once)
NULL
# Bottom line: You can use cat to display info to the screen# but don't expect that information to be "returned" from the function.# SOME TAKEAWAYS:# REMEMBER: ## A few things to remember ...## 1. If a function doesn't contain a return statement, then the # value of the final command to be executed in the function# is returned.## 2. Based on #1 above, the value that is returned from countdown()# is the value cat("blastoff!"). HOWEVER ... keep reading ...## 3. It is very important to understand that the cat function # does NOT "return" the information that is displayed. # # The purpose of cat is TO DISPLAY INFORMATION TO THE SCREEN.# The purpose of cat is NOT to return a value.# Programmers use the cat function to display information,# NOT to generate a "value".The actual return value of cat# is NULL. You never really need to use this NULL value,# but technically, NULL is the return value. ## 4. You don't actually see the word NULL on the screen when you # run the countdown function since the return value of cat is # an "invisible" value - we explained the concept of invisible# return values earlier in the semester when we first discussed# the cat function.)#-------------------------------------------------------------------#-------------------------------------------------------------------## END OF THE DIGRESSION ...# Let's get back to discussing the for loop and the while loop##-------------------------------------------------------------------#-------------------------------------------------------------------#------------------------------------------------------------# Write a function that takes a vector and returns a list# with 3 vectors. # (a) negative numbers# (b) nums between 0 and 100# (c) nums larger than 100# # DO NOT USE VECTOR OPERATIONS. RATHER, USE A LOOP.#------------------------------------------------------------splitVector =function ( vec ){ answer =list() answer$negNums = vec[ vec <0 ] answer$smallNums = vec[ vec>0& vec<100 ] answer$largeNums = vec[ vec >=100 ] answer}splitVector(c(-23, 197, -5, 92, 5, 3, -111, 1234, 5))
# Write the code again - this time use a loop to process the values in the # vector.splitVector =function( vec ){ answer =list()for( value in vec) {if( value <0 ) { answer$negValues =c(answer$negValues, value) } elseif( value <100 ){ answer$smallValues =c(answer$smallValues, value) } else { answer$largeValues =c(answer$largeValues, value) } } answer}splitVector(c(-23, 197, -5, 92, 5, 3, -111, 1234, 5))
#-------------------------------------------------------------# Rewrite the code to use a for loop instead of a while loop#-------------------------------------------------------------splitVector <-function( vec ){ answer <-list()for ( num in vec ) {# add num to either answer$negNums, answer$smallNums or answer$largeNumsif (num <0){ answer$negNums <-c(answer$negNums, num) } elseif ( num <=100 ) { answer$smallNums <-c(answer$smallNums, num) } else { answer$largeNums <-c(answer$largeNums, num) } }return(answer)}grades <-c(-10, 20, 1005, 32, -297)splitVector(grades)
########################################################################.# 2022 - BEREN - UP TO HERE - AFTER CLASS 27########################################################################.#----------------------------------------------------# Write isPrime(num) using a while loop# (we did this in an earlier class)#----------------------------------------------------isPrime <-function(num) { divisor <-2while ( divisor <sqrt(num) ){if (num %% divisor ==0){return(FALSE) } divisor <- divisor +1 }return(TRUE)}isPrime(35) # FALSE
[1] FALSE
isPrime(37) # TRUE
[1] TRUE
###############################################.isPrime_for =function( num ){for(divisor in2:sqrt(num)) {if ( num %% divisor ==0){return (FALSE) } }return(TRUE)}debugonce(isPrime_for)isPrime_for(49) # FALSE
debugging in: isPrime_for(49)
debug at <text>#1048: {
for (divisor in 2:sqrt(num)) {
if (num%%divisor == 0) {
return(FALSE)
}
}
return(TRUE)
}
debug at <text>#1050: for (divisor in 2:sqrt(num)) {
if (num%%divisor == 0) {
return(FALSE)
}
}
debug at <text>#1051: if (num%%divisor == 0) {
return(FALSE)
}
debug at <text>#1051: if (num%%divisor == 0) {
return(FALSE)
}
debug at <text>#1051: if (num%%divisor == 0) {
return(FALSE)
}
debug at <text>#1051: if (num%%divisor == 0) {
return(FALSE)
}
debug at <text>#1051: if (num%%divisor == 0) {
return(FALSE)
}
debug at <text>#1051: if (num%%divisor == 0) {
return(FALSE)
}
debug at <text>#1052: return(FALSE)
exiting from: isPrime_for(49)
[1] FALSE
isPrime_for(37) # TRUE
[1] TRUE
#----------------------------------------------------# rewrite the code for isPrime to use a for loop#----------------------------------------------------isPrime <-function(num) {for ( divisor in2:sqrt(num) ){if (num %% divisor ==0){return(FALSE) } }return(TRUE)}isPrime(35) # FALSE
[1] FALSE
isPrime(37) # TRUE
[1] TRUE
#------------------------------------------------------------# The unlist function can be used on a dataframe (since a dataframe is a list).# (see example below)## Write a function myUnlist that does the same thing as the unlist # function. However, your function does NOT need to create names for# the answer vector.## ARGUMENTS: lst is a list (remember a dataframe is also a list) ## The function should return a character vector that combines all# the values from the list (or all the columns from the dataframe)# into a single vector. #------------------------------------------------------------myUnlist =function( lst ) { answer =vector()for( listEntry in lst ){ answer =c(answer, listEntry) } answer}students <-data.frame(student=c("joe", "sue"),test1=c(100,90),test2 =c(85, 95),honors =c(FALSE, TRUE), stringsAsFactors =FALSE)students
student test1 test2 honors
1 joe 100 85 FALSE
2 sue 90 95 TRUE
#------------------------------------------------------------# Modify the code for dfToVec so that the vector # that is returned ONLY INCLUDES the values that# are in character columns of the dataframe.#------------------------------------------------------------dfToVec <-function ( df ){ answer <-character(0)for ( column in df ) {if ( is.character(column) ){ answer <-c(answer, column) } }return ( answer )}students <-data.frame(student=c("joe", "sue"),test1=c(100,90),test2 =c(85, 95),year =c("fr", "so"),honors =c(FALSE, TRUE), stringsAsFactors =FALSE)students
student test1 test2 year honors
1 joe 100 85 fr FALSE
2 sue 90 95 so TRUE
dfToVec(students)
[1] "joe" "sue" "fr" "so"
#------------------------------------------------------------# Write a function that takes a dataframe, df# and returns a character vector.# # The vector should contain# - all positive numbers from numeric columns# - all TRUE values from logical columns# - all character values that start with an "a" from character columns#------------------------------------------------------------dfToVec <-function( df ){ answer <-character(0)for ( column in df ) { # start of "outer" for loopfor ( value in column) { # start of "inner" for loopif( is.character(value) ){if ( value >="a"& value <"b" ){ answer <-c(answer, value) } } elseif ( is.numeric(value)) {if( value >0){ answer <-c(answer, value) } } elseif (is.logical(value) ) {if (value ==TRUE){ answer <-c(answer, value) } } } # end of "inner" for loop } # end of "outer" for loopreturn(answer)}students <-data.frame(student=c("joe", "alice", "mike", "anne"),test1=c(100,90,-20,-30),test2 =c(-10, -40, 85, 95),favFood =c("orange", "pear", "apple", "artichoke"),honors =c(TRUE, FALSE, FALSE, FALSE), stringsAsFactors =FALSE)students
student test1 test2 favFood honors
1 joe 100 -10 orange TRUE
2 alice 90 -40 pear FALSE
3 mike -20 85 apple FALSE
4 anne -30 95 artichoke FALSE
#------------------------------------------------------------# another way#------------------------------------------------------------# loop through the column numbers (outer loop)# loop through the row numbers (inner loop)# check a particular value from a given row,columndfToVec <-function( df ){ answer <-character(0)for ( colNumber in1:ncol(df)) { # "outer" for loopfor ( rowNumber in1:nrow(df)) { # "inner" for loop value = df[rowNumber, colNumber] # get a single valueif( is.character(value) ){if ( value >="a"& value <"b" ){ answer <-c(answer, value) } } elseif ( is.numeric(value)) {if( value >0){ answer <-c(answer, value) } } elseif (is.logical(value) ) {if (value ==TRUE){ answer <-c(answer, value) } } } # end of "inner" for loop } # end of "outer" for loopreturn(answer)}students <-data.frame(student=c("joe", "alice", "mike", "anne"),test1=c(100,90,-20,-30),test2 =c(-10, -40, 85, 95),favFood =c("orange", "pear", "apple", "artichoke"),honors =c(TRUE, FALSE, FALSE, FALSE), stringsAsFactors =FALSE)students
student test1 test2 favFood honors
1 joe 100 -10 orange TRUE
2 alice 90 -40 pear FALSE
3 mike -20 85 apple FALSE
4 anne -30 95 artichoke FALSE
############################################################################################################################################## *** IMPORTANT CONCEPTS ABOUT FOR LOOPS ***#### DO NOT CHANGE THE VALUE OF THE FOR LOOP **VARIABLE** IN THE BODY!!!## DO NOT CHANGE THE VALUE OF THE FOR LOOP **VECTOR** IN THE BODY!!!#### - The code in the body should NEVER change the value of the ## for loop variable directly.#### All changes to the value of the for loop variable should only## be done automatically by the for loop mechanism, ## i.e. the next value from the vector is AUTOMATICALLY assigned## to the for loop variable each time through the loop.#### Explicitly changing the value of the for loop variable in ## the body of the loop is very confusing and is considered## VERY VERY sloppy coding by programmers everywhere.#### - Similarly, the code in the body should NEVER change the value of the ## for loop vector. The vector should have a value when the for ## loop starts and the value of the vector should NEVER change ## as the for loop is executing.#### Changing the value of the vector of the for loop## in the body of the loop is very confusing and is considered## VERY VERY sloppy coding by programmers everywhere.## ############ *** DIFFERENCE BETEWEN FOR LOOPS AND WHILE LOOPS ***#### A for loop is a convenience but NOT a necessity. #### It IS TRUE that any code written with a for loop CAN be converted to use## a while loop instead.## ## HOWEVER, it is NOT TRUE that any code written with a while loop can be## converted to use a for loop.#### A for loop can only be used when you can anticipate how many times## the code will loop before the loop starts. #### For example, the guessing game program that we wrote in an earlier class## cannot be written with a for loop since it is impossible to know in## advance how many times the loop will need to "go around".#### isPrime CAN be written with a for loop since you know that you even## before the for loop needs to "go around" at most sqrt(n) times.#### firstNprimes cannot be written with a for loop since we have no idea## in advance how large the nth prime will be, e.g. how large is the ## one millionth prime number??? Therefore we cannot anticipate before ## the loop starts how many times the code needs to be repeated.###############################################################################################################################--------------------------------------------------------------# A plaindrome is a word that reads the same forwards and # backwards. # Example: racecar is a palindrome# pineapple is not# abcdxba is NOT a palindrome# abcdcba is a palindrome## Write a function isPalindrome(x)# # ARGUMENTS# - x is expected to be a character vector with one item in it## isPalindrome(x) should return TRUE if x is a palindrome# and return FALSE if it isn't#--------------------------------------------------------------#...............# strsplit #...............# strsplit will split up each value in a # character vector into multiple values.## IMPORTANT: The return value of strsplit is a LIST.?strsplit
starting httpd help server ... done
# multiple values in the original vectorpeople =c("Cohen,Sam","Jones,Bob","Andrews,Claire")people
# Note that strsplit returns a LIST even if there is only one # value in the character vectorfruit =c("apple,orange,pear")fruit
[1] "apple,orange,pear"
length(fruit)
[1] 1
splitFruit <-strsplit(fruit, ",")splitFruit
[[1]]
[1] "apple" "orange" "pear"
# display just the 2nd fruit (notice the [[double-brackets]][single-brackets])splitFruit[[1]][2]
[1] "orange"
# If the separator is the "empty string" (i.e. "") then # every character (e.g. letter, digit, space,!,@,#,$,%, etc)# is split into separate character valueswords =c("racecar", "pineapple", "cart")strsplit(words,"")
[[1]]
[1] "r" "a" "c" "e" "c" "a" "r"
[[2]]
[1] "p" "i" "n" "e" "a" "p" "p" "l" "e"
[[3]]
[1] "c" "a" "r" "t"
# Remember that strsplit returns a list EVEN if there# is only one character value being split. You will need to # keep this in mind when writing the code.word <-"racecar"y <-strsplit(word,"")y
[[1]]
[1] "r" "a" "c" "e" "c" "a" "r"
y[1] # still a list
[[1]]
[1] "r" "a" "c" "e" "c" "a" "r"
y[[1]] # the vector without the surrounding list
[1] "r" "a" "c" "e" "c" "a" "r"
unlist(y) # the vector without the surrounding list
[1] "r" "a" "c" "e" "c" "a" "r"
# display the 2nd letter of the wordy[[1]][2] # one way
[1] "a"
unlist(y)[2] # another way
[1] "a"
z <- y[[1]] # you could use a variablez[2]
[1] "a"
#.........................................................## Let's get back to coding the isPalindrome function ...## ... first let's do it with a while loop##.........................................................isPalindrome <-function(x) {if (!is.character(x) |length(x) !=1){stop("x must have a single character value") } lets <-strsplit(x, "")[[1]] # get the individual letters in a vector left =1 right =length(lets)while ( left < right) {if(lets[left] != lets[right]){return(FALSE) } left = left +1 right = right -1 }return(TRUE)}isPalindrome("abcdxba") # FALSE
[1] FALSE
isPalindrome("abcdcba") # TRUE
[1] TRUE
isPalindrome("racecar") # TRUE
[1] TRUE
isPalindrome("amanaplanacanalpanama") # TRUE
[1] TRUE
isPalindrome("a man a plan a canal panama") # FALSE - because of the spaces
[1] FALSE
#.........................................................# Rewrite the function so that it removes spaces before# checking to see if x is a palindrome#.........................................................isPalindrome <-function(x) {if (!is.character(x) |length(x) !=1){stop("x must have a single character value") } lets <-strsplit(x, "")[[1]] lets <- lets [ lets !=" " ] # get rid of the spaces from lets left =1 right =length(lets)while ( left < right) {if(lets[left] != lets[right]){return(FALSE) } left = left +1 right = right -1 }return(TRUE)}isPalindrome("a man a plan a canal panama") # TRUE
[1] TRUE
#................................................## Rewrite the code to use a for loop##................................................isPalindrome <-function(x) {if (!is.character(x) |length(x) !=1){stop("x must have a single character value") } lets <-strsplit(x, "")[[1]] # get the individual letters in a vector# get rid of the spaces from lets lets <- lets [ lets !=" " ]for ( num in1:trunc(length(lets)/2) ){# note: num will start at 1, then 2, then 3, up until 1/2 the length of the word# exmpale: for "racecar" num will be 1 then 2 then 3 then stop first = num last =length(lets)-num+1if( lets[first] != lets[last]){return(FALSE) } }return(TRUE) }isPalindrome("abcdxba") # FALSE
[1] FALSE
isPalindrome("abcdcba") # TRUE
[1] TRUE
isPalindrome("racecar") # TRUE
[1] TRUE
isPalindrome("amanaplanacanalpanama") # TRUE
[1] TRUE
isPalindrome("a man a plan a canal panama") # TRUE