23  [[double-brackets]]

###############################################################################.
###############################################################################.
## 
## INTRODUCING [[double-bracket]] NOTATION FOR INDEXING LISTS (and also vectors)
##
## A new notation that we have not seen yet for indexing both vectors and lists
## is to use [[double-brackets]] to contain the index information instead
## of [single-brackets]. For example
##
##    someObject[3]     # [single-bracket] notation
##    someObject[[3]]   # [[double-bracket]] notation
##
## [[double-brackets]] have a slightly different meaning from [single-brackets].
##
## [[double-brackets]] work a little differently with vectors and with lists.
##
###############################################################################.
###############################################################################.
#----------------------------------------------------------------------.
# USING [[double-brackets]] WITH LISTS 
#
# Using [[double-brackets]] to index into a LIST is similar to using 
# double-brackets to index into a vector in the following way:
#
#     - You CAN use POSITIVE NUMBERS numbers in the [[double-brackets]]
#       With a LIST you MAY specify more than one POSITIVE number in the
#       [[double-brackets]]. (With vectors you are only able to specify
#       one positive number). We'll discuss below exactly how this works.
#
#  HOWEVER 
#
#     - You CANNOT use negative numbers in the [[double-brackets]]
#
#     - You CANNOT use logical values in the [[double-brackets]]
#
#----------------------------------------------------------------------.

# setup a list to work with

gradebook = list( c("bob", "charlie", "frank"), # student names
                  c(70,80,90),                  # grades from first test
                  c(75,85,88),                  # grades from second test
                  c(TRUE, FALSE,FALSE))         # TRUE for honors students

gradebook
[[1]]
[1] "bob"     "charlie" "frank"  

[[2]]
[1] 70 80 90

[[3]]
[1] 75 85 88

[[4]]
[1]  TRUE FALSE FALSE
# The following are ERRORS!

gradebook[[-1]]    # ERROR - don't use negative values in the [[double-brackets]]
Error in gradebook[[-1]]: invalid negative subscript in get1index <real>
gradebook[[c(TRUE,FALSE)]] # ERROR - don't use logicals in [[double-brackets]]
Error in gradebook[[c(TRUE, FALSE)]]: attempt to select less than one element in integerOneIndex

23.1 someList[1] vs someList[[1]]

#............................................................................
# QUESTION
#
# Take a minute to CAREFULLY NOTICE the difference between the following 
# two commands. 
# 
# What is the difference??? 
#
#      > gradebook[1]
#      [[1]]
#      [1] "bob"     "charlie" "frank"  
#
#
#      > gradebook[[1]]
#      [1] "bob" "charlie" "frank"
#
#............................................................................

gradebook[1]  # return value is shown below
[[1]]
[1] "bob"     "charlie" "frank"  
# > gradebook[1]
# [[1]]
# [1] "bob"     "charlie" "frank"  


gradebook[[1]]  # return value is shown below
[1] "bob"     "charlie" "frank"  
# > gradebook[[1]]
# [1] "bob" "charlie" "frank"



#............................................................................
# ANSWER TO QUESTION
#
#    gradebook[1]    # returns a LIST of that contains ONE VECTOR
#
#    gradebook[[1]]  # returns ONE VECTOR
#............................................................................

mode( gradebook [1])   # returns a list
[1] "list"
mode( gradebook [[1]]) # returns a character vector
[1] "character"
# Similarly for other positions ....

gradebook[[2]]      # 70 80 90
[1] 70 80 90
mode( gradebook [2])   # list
[1] "list"
mode( gradebook [[2]]) # numeric
[1] "numeric"

23.2 USING [single-brackets] TO INDEX INTO A LIST USING MORE THAN ONE POSITIVE NUMBER

#---------------------------------------------------------------------.
# USING [single-brackets] TO INDEX INTO A LIST 
# USING MORE THAN ONE POSITIVE NUMBER
# is conceptually similar to using more than one positive number in single brackets
# with VECTORS.
#
# When indexing into a VECTOR you get back just the specified values in a new VECTOR.
#
# When indexing into a LIST  you get back just the specified values in a new LIST.
#---------------------------------------------------------------------.

gradebook[ c(1,2) ]   # a list of 2 items, i.e. the names and the test1 grades
[[1]]
[1] "bob"     "charlie" "frank"  

[[2]]
[1] 70 80 90
mode(gradebook[c(1,2)])  # list
[1] "list"

23.3 USING [[double-brackets]] TO INDEX INTO A LIST USING MORE THAN ONE POSITIVE NUMBER

#---------------------------------------------------------------------.
# RECURSIVE INDEXING
#
# WITH LISTS YOU CAN USE THE [[double-brackets]] with more than
# one position number - it applies the position numbers to the items
# you get back one at a time. This is known as "recursive indexing".
#---------------------------------------------------------------------.

gradebook[[c(1,2)]] # "charlie" - ie. from the 1st item in the list get the 2nd item
[1] "charlie"
gradebook[[c(3,3)]] # 88 - i.e. from the 3rd item in the list get the 3rd item
[1] 88
gradebook[[c(3,2)]] # 85 - i.e. from the 3rd item in the list get the 2nd item
[1] 85
gradebook[[3]]      # 75 85 95
[1] 75 85 88
gradebook[[4]]      # TRUE FALSE FALSE
[1]  TRUE FALSE FALSE

23.4 Using the length function with lists (it can be tricky)

#--------------------------------------------.
# length( SOME_LIST )
#    returns the number of objects in the list
#
#     vs
# 
# length( SOME_LIST[[1]] )
#    returns the number of items in the first object in the list
#
#    vs
#
# length( SOME_LIST[1] )
#    DONT DO THIS - IT ALWAYS RETURNS 1  - WHY?
#------------------------------------------------

rm(list=ls()) # Start from scratch
gradebook = list( c("bob", "charlie", "frank"), # student names
                  c(70,80,90),                  # grades from first test
                  c(75,85,88),                  # grades from second test
                  c(TRUE, FALSE,FALSE))         # TRUE for honors students


##############################################.
# Let's see the lengths of the following ...
##############################################.
length(gradebook)       # 4 - i.e. four objects in the list 
[1] 4
length(gradebook[[1]])  # 3 - i.e. three student names in the first object of the list
[1] 3
# Be careful - if you use single brackets you will get back a "list". 
# Therefore the following all return a list of length 1.
length(gradebook[1])    # 1 - i.e. this is a LIST that contains one vector
[1] 1
#############################.
# Let's see the actual values
#############################.

# The full gradebook
gradebook       
[[1]]
[1] "bob"     "charlie" "frank"  

[[2]]
[1] 70 80 90

[[3]]
[1] 75 85 88

[[4]]
[1]  TRUE FALSE FALSE
# The first item in the list (i.e. a full vector)
gradebook[[1]]  
[1] "bob"     "charlie" "frank"  
# A new list that contains just the 1st item of the original list vector)
gradebook[1]    
[[1]]
[1] "bob"     "charlie" "frank"  
#etc

23.5 Summary - [single-brackets] vs [[double-brackets]]

###############################################################################.
#
# If you keep the following idea in mind, a lot of the rules become 
# easier to remember:
#
#   - [single-brackets] are intended to allow you to identify MULTIPLE objects
#     in a list (and in a vector).
#
#   - [[double-brackets]] are intended to allow you to identify A SINGLE object
#     in a list (and in a vector too - we'll see this later). However, when
#     using a list, a SINGLE object might be a complete vector (or even 
#     a complete list)
###############################################################################.

23.6 — Practice —

#########################################################.
# Use the following to answer the questions below
#########################################################.
rm(list=ls()) # Start from scratch
gradebook = list( c("bob", "charlie", "frank", "sam"),# student names
                  c(70,     80,        90,      100), # grades from 1st test
                  c(75,     85,        88,      92),  # grades from 2nd test
                  c(TRUE,   FALSE,     FALSE,   TRUE))# TRUE for honors students
str(gradebook)  # see the structure
List of 4
 $ : chr [1:4] "bob" "charlie" "frank" "sam"
 $ : num [1:4] 70 80 90 100
 $ : num [1:4] 75 85 88 92
 $ : logi [1:4] TRUE FALSE FALSE TRUE
gradebook # (see the actual values)
[[1]]
[1] "bob"     "charlie" "frank"   "sam"    

[[2]]
[1]  70  80  90 100

[[3]]
[1] 75 85 88 92

[[4]]
[1]  TRUE FALSE FALSE  TRUE
# View(gradebooks)  # see the structure - try this command yourself
##########################################################################.
# QUESTION
#
# NOTE that many R commands and functions require a vector, not a list.
# Therefore in these situations you will need to retrieve a vector
# from the list using [[double-brackets]]
#
# Given the gradebook data shown above, write a command to calculate
# the average on the 1st exam.
##########################################################################.
###########.
# ANSWER
###########.

# Use [[double-brackets]] to get the data for the first exam
# and take the mean.

mean(gradebook[[2]])
[1] 85
##############################.
# THE FOLLOWING IS WRONG!!!!
##############################.

# Note that the following does NOT produce the correct results
# since gradebook[2] is a LIST and you cannot take the mean of a list.

mean(gradebook[2])  # WRONG - gradebook[2] is a LIST - you need a VECTOR
Warning in mean.default(gradebook[2]): argument is not numeric or logical:
returning NA
[1] NA
##########################################################################.
# QUESTION
#
# Notice that the data in the list above is a set of parallel vectors.
# Write a command to show the name of the students who got above average
# on the 1st test.
##########################################################################.
#####################################.
# ANSWER (using a few lines of code)
#####################################.

students = gradebook[[1]]
test1 = gradebook[[2]]

students [ test1 > mean(test1) ]  # show the students names
[1] "frank" "sam"  
#####################################.
# ANSWER (in one line of code)
#####################################.

gradebook[[1]] [  gradebook[[2]] > mean(gradebook[[2]])  ]
[1] "frank" "sam"  
#############################################################################.
# QUESTION 
# Write a command to return a vector that contains both the test1 and test2 
# grades for the 3rd student
#############################################################################.
###########.
# ANSWER
###########.
c( gradebook[[c(2,3)]] , gradebook[[c(3,3)]] )
[1] 90 88

23.7 — Practice —

#########################################################.
# Use the following to answer the questions below
#########################################################.
rm(list=ls())  # start from scratch

gradebooks = list( 
                    c("Intro to IDS", "Prof. Jones"),
                    list( "Fall 2023",
                          c("bob", "charlie", "frank"), # student names
                          c(70,80,90),                  # grades from first test
                          c(75,85,88),                  # grades from second test
                          c(TRUE, FALSE,FALSE)),         # TRUE for honors students
                    list("Spring 2024",
                          c("bob", "charlie", "frank"), # student names
                          c(70,80,90),                  # grades from first test
                          c(75,85,88),                  # grades from second test
                          c(TRUE, FALSE,FALSE))         # TRUE for honors students
             )
str(gradebooks)  # see the structure
List of 3
 $ : chr [1:2] "Intro to IDS" "Prof. Jones"
 $ :List of 5
  ..$ : chr "Fall 2023"
  ..$ : chr [1:3] "bob" "charlie" "frank"
  ..$ : num [1:3] 70 80 90
  ..$ : num [1:3] 75 85 88
  ..$ : logi [1:3] TRUE FALSE FALSE
 $ :List of 5
  ..$ : chr "Spring 2024"
  ..$ : chr [1:3] "bob" "charlie" "frank"
  ..$ : num [1:3] 70 80 90
  ..$ : num [1:3] 75 85 88
  ..$ : logi [1:3] TRUE FALSE FALSE
gradebooks # (see the actual values)
[[1]]
[1] "Intro to IDS" "Prof. Jones" 

[[2]]
[[2]][[1]]
[1] "Fall 2023"

[[2]][[2]]
[1] "bob"     "charlie" "frank"  

[[2]][[3]]
[1] 70 80 90

[[2]][[4]]
[1] 75 85 88

[[2]][[5]]
[1]  TRUE FALSE FALSE


[[3]]
[[3]][[1]]
[1] "Spring 2024"

[[3]][[2]]
[1] "bob"     "charlie" "frank"  

[[3]][[3]]
[1] 70 80 90

[[3]][[4]]
[1] 75 85 88

[[3]][[5]]
[1]  TRUE FALSE FALSE
# View(gradebooks)  # see the structure - try this command yourself
mean( gradebooks[[2]][[3]] )
[1] 80
max( gradebooks[[2]][[3]], gradebooks[[2]][[4]] )
[1] 90
length(gradebooks)
[1] 3
length(gradebooks[c(1,2)])  
[1] 2
gradebooks[c(1,2)]
[[1]]
[1] "Intro to IDS" "Prof. Jones" 

[[2]]
[[2]][[1]]
[1] "Fall 2023"

[[2]][[2]]
[1] "bob"     "charlie" "frank"  

[[2]][[3]]
[1] 70 80 90

[[2]][[4]]
[1] 75 85 88

[[2]][[5]]
[1]  TRUE FALSE FALSE
str(gradebooks[c(1,2)])
List of 2
 $ : chr [1:2] "Intro to IDS" "Prof. Jones"
 $ :List of 5
  ..$ : chr "Fall 2023"
  ..$ : chr [1:3] "bob" "charlie" "frank"
  ..$ : num [1:3] 70 80 90
  ..$ : num [1:3] 75 85 88
  ..$ : logi [1:3] TRUE FALSE FALSE
gradebooks[c(1,3)]
[[1]]
[1] "Intro to IDS" "Prof. Jones" 

[[2]]
[[2]][[1]]
[1] "Spring 2024"

[[2]][[2]]
[1] "bob"     "charlie" "frank"  

[[2]][[3]]
[1] 70 80 90

[[2]][[4]]
[1] 75 85 88

[[2]][[5]]
[1]  TRUE FALSE FALSE
str(gradebooks[c(1,3)])
List of 2
 $ : chr [1:2] "Intro to IDS" "Prof. Jones"
 $ :List of 5
  ..$ : chr "Spring 2024"
  ..$ : chr [1:3] "bob" "charlie" "frank"
  ..$ : num [1:3] 70 80 90
  ..$ : num [1:3] 75 85 88
  ..$ : logi [1:3] TRUE FALSE FALSE
length(gradebooks[[c(1,2)]])
[1] 1
gradebooks[[c(1,2)]]
[1] "Prof. Jones"
str(gradebooks[[c(1,2)]])
 chr "Prof. Jones"
length(gradebooks[[2]])
[1] 5
gradebooks[[2]][3]
[[1]]
[1] 70 80 90
mode( gradebooks[[2]][3] )
[1] "list"
length( gradebooks[[2]][3] )
[1] 1
gradebooks[[2]][[3]]  
[1] 70 80 90
mode( gradebooks[[2]][[3]] )  
[1] "numeric"
length( gradebooks[[2]][3] )  
[1] 1