How to append value of every two columns in R?

66 Views Asked by At

go from

m <- matrix(1:16, nrow = 4)

     [,1] [,2] [,3] [,4]
[1,]    1    5    9   13
[2,]    2    6   10   14
[3,]    3    7   11   15
[4,]    4    8   12   16

to

1x16 matrix 1 5 2 6 3 7 4 8 9 13 10 14 11 15 12 16

tried to flatten this but didn't work

> flattened_matrix <- matrix(m, nrow = 1, byrow = TRUE)
> flattened_vector <- as.vector(t(flattened_matrix))

3

There are 3 best solutions below

0
Mark On

Update:

Okay so the order you are wanting is quite strange. I'm unsure what the underlying rules are, but I'm assuming here you are wanting to grab the values in the first two columns, then the next set of two columns, etc.

ans <- sapply(seq(2, ncol(m), 2), \(n) as.vector(t(m[,(n-1):n])))

as.vector(ans)
[1]  1  5  2  6  3  7  4  8  9 13 10 14 11 15 12 16
# or
matrix(ans, nrow = 1)
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
[1,]    1    5    2    6    3    7    4    8    9    13    10    14    11    15
     [,15] [,16]
[1,]    12    16

Original:

The heart of this problem is with the function matrix()'s argument byrow. From the documentation:

byrow: logical. If FALSE (the default) the matrix is filled by columns, otherwise the matrix is filled by rows.

Note that with a one row or one column matrix, filling by row or by column is the same thing. The byrow argument decides how we fill the output matrix, not the order in which we take elements from the input matrix.

To get this working, you could do many things. One option is transposing the matrix m first, and another is creating a new 4x4 matrix with byrow = TRUE then turning that into a one row matrix or a vector:

matrix(t(m), nrow = 1)
# or
as.vector(t(m))
# or
matrix(m, nrow = 4, byrow = T) |> matrix(nrow = 1)
# or
matrix(m, nrow = 4, byrow = T) |> as.vector()

Output(s):

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
[1,]    1    5    9   13    2    6   10   14    3     7    11    15     4     8
     [,15] [,16]
[1,]    12    16
# or
[1]  1  5  9 13  2  6 10 14  3  7 11 15  4  8 12 16
0
Onyambu On
m[order((col(m) - 1)%/%2, row(m))]
 [1]  1  5  2  6  3  7  4  8  9 13 10 14 11 15 12 16

c(aperm(array(t(m), c(ncol(m)/2, 2, nrow(m))), c(1, 3, 2)))
 [1]  1  5  2  6  3  7  4  8  9 13 10 14 11 15 12 16
1
ThomasIsCoding On

Here are some base R options

> Reduce(c, split(t(m), ceiling(seq.int(ncol(m)) / 2)))
 [1]  1  5  2  6  3  7  4  8  9 13 10 14 11 15 12 16
> unname(unlist(split(t(m), ceiling(seq.int(ncol(m)) / 2))))
 [1]  1  5  2  6  3  7  4  8  9 13 10 14 11 15 12 16
> unname(do.call(c, split(t(m), ceiling(seq.int(ncol(m)) / 2))))
 [1]  1  5  2  6  3  7  4  8  9 13 10 14 11 15 12 16
> c(apply(array(m, c(nrow(m), 2, ncol(m) / 2)), 3, t))
 [1]  1  5  2  6  3  7  4  8  9 13 10 14 11 15 12 16
> c(t(m))[order(gl(ncol(m) / 2, 2, length(m)))]
 [1]  1  5  2  6  3  7  4  8  9 13 10 14 11 15 12 16