Details on Casting Functions

Description

‘broadcast’ provides several "casting" functions.
These can facilitate complex forms of broadcasting that would normally not be possible.
But these "casting" functions also have their own merit, beside empowering complex broadcasting.

The following casting functions are available:

  • acast:
    Casts group-based subsets of an array into a new dimension.
    Useful for, for example, performing grouped broadcasted operations.

  • cast_hier2dim:
    Casts a nested/hierarchical list into a dimensional list (i.e. array of type list).
    Useful because one cannot broadcast through nesting, but one can broadcast along dimensions.

  • hier2dim, hiernames2dimnames:
    Helper functions for cast_hier2dim.

  • cast_dim2hier:
    Casts a dimensional list into a nested/hierarchical list; the opposite of cast_hier2dim.

  • cast_shallow2atomic:
    Casts a (dimensional) shallow (i.e. non-nested) list into an atomic vector or array.
    Useful because atomic vectors/arrays have access to many vectorized (broadcasted) operations that may not be available for vectors/arrays of type list.

  • cast_dim2flat:
    Casts a dimensional list into a flattened list, but with names that indicate their original dimensional positions.
    Mostly useful for printing or summarizing dimensional lists.

  • dropnests:
    Drop redundant nesting in lists; mostly used for facilitating the above casting functions.

Shared argument recurse_all

The dropnests, hier2dim, hiernames2dimnames, and cast_hier2dim methods all have the recurse_all argument.
By default recurse_all = FALSE, meaning these methods do not recurse through dimensional or classed lists (like data.frames).
Setting recurse_all = TRUE allows these methods to recurse through all list objects, even if they are dimensional and/or classed.

Shared Argument in2out

The hier2dim, hiernames2dimnames, cast_hier2dim, and cast_dim2hier methods all have the in2out argument.


[TRUE]
By default in2out is TRUE.
This means the call
y <- cast_hier2dim(x)
will cast the elements of the deepest valid depth of x to the rows of y, and elements of the depth above that to the columns of y, and so on until the surface-level elements of x are cast to the last dimension of y.

Similarly, the call
x <- cast_dim2hier(y)
will cast the rows of y to the inner most elements of x, and the columns of y to one depth above that, and so on until the last dimension of y is cast to the surface-level elements of x.

Consider the nested list x with a depth of 3, and the recursive array y with 3 dimensions, where their relationship can described as the following code:
y <- cast_hier2dim(x)
x <- cast_dim2hier(y).
Then it holds that:
x[[i]][[j]][[k]] corresponds to y[[k, j, i]],
\(\forall\)(i, j, k) , provided x[[i]][[j]][[k]] exists.


[FALSE]
If in2out = FALSE, the call
y <- cast_hier2dim(x, in2out = FALSE)
will cast the surface-level elements of x to the rows of y, and elements of the depth below that to the columns of y, and so on until the elements of the deepest valid depth of x are cast to the last dimension of y.

Similarly, the call
x <- cast_dim2hier(y, in2out = FALSE)
will cast the rows of y to the surface-level elements of x, and the columns of y to one depth below that, and so on until the last dimension of y is cast to the inner most elements of x.

Consider the nested list x with a depth of 3, and the recursive array y with 3 dimensions, where their relationship can described with the following code:
y <- cast_hier2dim(x, in2out = FALSE)
x <- cast_dim2hier(y, in2out = FALSE).
Then it holds that :
x[[i]][[j]][[k]] corresponds to y[[i, j, k]],
\(\forall\)(i, j, k) , provided x[[i]][[j]][[k]] exists.

Examples

library("broadcast")


# recurse_all demonstration ====
x <- list(
  a = list(list(list(list(1:10)))),
  b = data.frame(month.abb, month.name),
  c = data.frame(month.abb),
  d = array(list(1), c(1,1,1))
)

dropnests(x) # by default, recurse_all = FALSE
## $a
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## $b
##    month.abb month.name
## 1        Jan    January
## 2        Feb   February
## 3        Mar      March
## 4        Apr      April
## 5        May        May
## 6        Jun       June
## 7        Jul       July
## 8        Aug     August
## 9        Sep  September
## 10       Oct    October
## 11       Nov   November
## 12       Dec   December
## 
## $c
##    month.abb
## 1        Jan
## 2        Feb
## 3        Mar
## 4        Apr
## 5        May
## 6        Jun
## 7        Jul
## 8        Aug
## 9        Sep
## 10       Oct
## 11       Nov
## 12       Dec
## 
## $d
## , , 1
## 
##      [,1]
## [1,] 1

dropnests(x, recurse_all = TRUE) # recurse_all = TRUE
## $a
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## $b
##    month.abb month.name
## 1        Jan    January
## 2        Feb   February
## 3        Mar      March
## 4        Apr      April
## 5        May        May
## 6        Jun       June
## 7        Jul       July
## 8        Aug     August
## 9        Sep  September
## 10       Oct    October
## 11       Nov   November
## 12       Dec   December
## 
## $c
##  [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
## 
## $d
## [1] 1



# in2out demonstration ====
x <- list(
  group1 = list(
    class1 = list(
      height = rnorm(10, 170),
      weight = rnorm(10, 80),
      sex = sample(c("M", "F", NA), 10, TRUE)
    ),
    class2 = list(
      height = rnorm(10, 170),
      weight = rnorm(10, 80),
      sex = sample(c("M", "F", NA), 10, TRUE)
    )
  ),
  group2 = list(
    class1 = list(
      height = rnorm(10, 170),
      weight = rnorm(10, 80),
      sex = sample(c("M", "F", NA), 10, TRUE)
    ),
    class2 = list(
      height = rnorm(10, 170),
      weight = rnorm(10, 80),
      sex = sample(c("M", "F", NA), 10, TRUE)
    )
  )
)

# in2out = TRUE (default):
x2 <- cast_hier2dim(x)
dimnames(x2) <- hiernames2dimnames(x)
print(x2)
## , , group1
## 
##        class1       class2      
## height numeric,10   numeric,10  
## weight numeric,10   numeric,10  
## sex    character,10 character,10
## 
## , , group2
## 
##        class1       class2      
## height numeric,10   numeric,10  
## weight numeric,10   numeric,10  
## sex    character,10 character,10
cast_dim2flat(x2[1,1,,drop = FALSE])
## $`['height', 'class1', 'group1']`
##  [1] 169.2109 169.8914 170.6304 170.1353 169.8938 170.5809 169.0212 169.9166
##  [9] 170.1503 170.6861
## 
## $`['height', 'class1', 'group2']`
##  [1] 169.1964 169.7552 170.6040 169.4092 169.8745 169.5932 170.7810 169.1108
##  [9] 170.0414 169.7125

# in2out = FALSE:
x2 <- cast_hier2dim(x, in2out = FALSE)
dimnames(x2) <- hiernames2dimnames(x, in2out = FALSE)
print(x2)
## , , height
## 
##        class1     class2    
## group1 numeric,10 numeric,10
## group2 numeric,10 numeric,10
## 
## , , weight
## 
##        class1     class2    
## group1 numeric,10 numeric,10
## group2 numeric,10 numeric,10
## 
## , , sex
## 
##        class1       class2      
## group1 character,10 character,10
## group2 character,10 character,10
cast_dim2flat(x2[1,1,,drop = FALSE])
## $`['group1', 'class1', 'height']`
##  [1] 169.2109 169.8914 170.6304 170.1353 169.8938 170.5809 169.0212 169.9166
##  [9] 170.1503 170.6861
## 
## $`['group1', 'class1', 'weight']`
##  [1] 79.86818 81.38589 80.84735 80.10565 80.49537 80.85883 80.28186 80.32956
##  [9] 80.13475 79.12128
## 
## $`['group1', 'class1', 'sex']`
##  [1] "M" "M" "F" NA  NA  NA  "F" "F" "M" "F"