I have the need to grab all the three element triangles that make up the lower triangle of a symmetric matrix. I can not think of how to grab all these pieces in the order of far left column working down and then next column to the right and so on. I know that the numbe rof mini triangles inside of the lower triangle is:
n = x(x - 1)/2
where: x = nrow(mats[[i]])
Here I've created three matrices with letters (it's easier for me to conceptualize this way) and the elements in the order I'm looking for:
FUN <- function(n) {
matrix(LETTERS[1:(n*n)], n)
}
mats <- lapply(3:5, FUN)
So this is the output I'd like to get (I put it in code rather than output format) for each of the matrices created above:
list(c("B", "C", "F"))
list(c("B", "C", "G"), c("C", "D", "H"), c("G", "H", "L"))
list(c("B", "C", "H"), c("C", "D", "I"), c("D", "E", "J"),
c("H", "I", "N"), c("I", "J", "O"), c("N", "O", "T"))
How can I do this task in the fastest manner possible while staying in base R?
Not sure if this visual of what I'm after is helpful but it may be:
Nice problem! Here is how you can solve it using a bit of recursion (followed by a MUCH simpler version)
triangle <- function(base.idx, mat) {
upper.idx <- base.idx - 1L
right.idx <- base.idx + nrow(mat)
paste(mat[c(upper.idx, base.idx, right.idx)], collapse = " ")
}
get.triangles <- function(mat) {
N <- nrow(mat)
if (N == 3L) {
return(triangle(3L, mat))
} else {
left.idx <- 3:N
right.mat <- mat[2:N, 2:N]
left.triangles <- sapply(left.idx, triangle, mat)
right.triangles <- Recall(right.mat)
return(c(left.triangles, right.triangles))
}
}
x <- lapply(mats, get.triangles)
# [[1]]
# [1] "B C F"
#
# [[2]]
# [1] "B C G" "C D H" "G H L"
#
# [[3]]
# [1] "B C H" "C D I" "D E J" "H I N" "I J O" "N O T"
I'll just comment on the output not being exactly as you asked. It is because creating recursive functions that return a flat list are always difficult to work with: somehow you always end up with nested lists...
So the last step should be:
lapply(x, strsplit, split = " ")
and it will be in the same format you asked for.
And here is an even simpler version (forget about recursion!)
get.triangles <- function(mat) {
base.idx <- seq_along(mat)[row(mat) > col(mat) + 1]
upper.idx <- base.idx - 1L
right.idx <- base.idx + nrow(mat)
lapply(mapply(c, upper.idx, base.idx, right.idx, SIMPLIFY = FALSE),
function(i)mat[i])
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With