When creating a function in R, though you cannot return more than one output, you can return a list. This (by definition) can contain an arbitrary number of arbitrary objects
# Define some functions
identity.1 = function(x, y) { list(x, y) }
identity.2 = function(x, y) { list(x=x, y=y) }
identity.3 = function(x, y) { return(x, y) }
# Now let's run them
identity.1(1, 2)
## [[1]]
## [1] 1
##
## [[2]]
## [1] 2
identity.2(1, 2) # Notice the names (helpful)
## $x
## [1] 1
##
## $y
## [1] 2
identity.2(1, "2") # Notice the mixed data types
## $x
## [1] 1
##
## $y
## [1] "2"
identity.2(1, 2:8) # Again, the mixed data types
## $x
## [1] 1
##
## $y
## [1] 2 3 4 5 6 7 8
Running the following code would produce an error:
identity.3(1, 2)
## Error in return(x, y): multi-argument returns are not permitted
# get.wordtab: get a word table from text on the web
# Inputs:
# - str.url: string, specifying URL of a web page
# - split: string, specifying what to split on. Default is the regex pattern
# "[[:space:]]|[[:punct:]]"
# - tolower: boolean, TRUE if words should be converted to lower case before
# the word table is computed. Default is TRUE
# - keep.numbers: boolean, TRUE if words containing numbers should be kept in
# the word table. Default is FALSE
# Output: list, containing word table, and then some basic numeric summaries
get.wordtab = function(str.url, split="[[:space:]]|[[:punct:]]",
tolower=TRUE, keep.numbers=FALSE) {
lines = readLines(str.url)
text = paste(lines, collapse=" ")
words = strsplit(text, split=split)[[1]]
words = words[words != ""]
# Convert to lower case, if we're asked to
if (tolower) words = tolower(words)
# Get rid of words with numbers, if we're asked to
if (!keep.numbers)
words = grep("[0-9]", words, inv=TRUE, val=TRUE)
# Compute the word table
wordtab = table(words)
return(list(wordtab=wordtab,
number.unique.words=length(wordtab),
number.total.words=sum(wordtab)))
}
# Trump's speech
trump.wordtab = get.wordtab("http://www.stat.cmu.edu/~ryantibs/statcomp-F16/data/trump.txt")
lapply(trump.wordtab, head)
## $wordtab
## words
## a abandon abandoned able abolish about
## 54 1 1 2 1 4
##
## $number.unique.words
## [1] 1236
##
## $number.total.words
## [1] 4431
# Clinton's speech
clinton.wordtab = get.wordtab("http://www.stat.cmu.edu/~ryantibs/statcomp-F16/data/clinton.txt")
lapply(clinton.wordtab, head)
## $wordtab
## words
## a abandoned able about abroad accept
## 106 1 1 11 1 1
##
## $number.unique.words
## [1] 1306
##
## $number.total.words
## [1] 5555
A side effect of a function is something that happens as a result of the function’s body, but is not returned
Examples:
# get.wordtab: get a word table from text on the web
# Inputs:
# - str.url: string, specifying URL of a web page
# - split: string, specifying what to split on. Default is the regex pattern
# "[[:space:]]|[[:punct:]]"
# - tolower: boolean, TRUE if words should be converted to lower case before
# the word table is computed. Default is TRUE
# - keep.numbers: boolean, TRUE if words containing numbers should be kept in
# the word table. Default is FALSE
# - plot.wordtab: boolean, TRUE if word table should be plotted as a side
# effect. Default is FALSE
# Output: list, containing word table, and then some basic numeric summaries
get.wordtab = function(str.url, split="[[:space:]]|[[:punct:]]",
tolower=TRUE, keep.numbers=FALSE, plot.wordtab=FALSE) {
lines = readLines(str.url)
text = paste(lines, collapse=" ")
words = strsplit(text, split=split)[[1]]
words = words[words != ""]
# Convert to lower case, if we're asked to
if (tolower) words = tolower(words)
# Get rid of words with numbers, if we're asked to
if (!keep.numbers)
words = grep("[0-9]", words, inv=TRUE, val=TRUE)
# Compute the word table
wordtab = table(words)
# Plot the word table, if we're asked to
if (plot.wordtab) plot(wordtab)
return(list(wordtab=wordtab,
number.unique.words=length(wordtab),
number.total.words=sum(wordtab)))
}
# Trump's speech
trump.wordtab = get.wordtab(
"http://www.stat.cmu.edu/~ryantibs/statcomp-F16/data/trump.txt",
plot=TRUE)
lapply(trump.wordtab, head)
## $wordtab
## words
## a abandon abandoned able abolish about
## 54 1 1 2 1 4
##
## $number.unique.words
## [1] 1236
##
## $number.total.words
## [1] 4431
Not all side effects are desirable. One particularly bad side effect is if the function’s body changes the value of some variable defined outside of the function
Not easy to do, but can be done and should be avoided! (We’ll discuss function enviroments next time)