3

Given only the following vector:

v <- c(2, 4, 6, 8)

The following matrix is desired in which the row-wise directions are alternately right-to-left and left-to-right (by traversing the matrix from top to bottom) and the anti-diagonal is set to zero.

8  6  4  2  0
2  4  6  0  8
8  6  0  4  2
2  0  4  6  8
0  8  6  4  2

How this can be accomplished efficiently in R?

989
  • 12,579
  • 5
  • 31
  • 53
  • Relevant post: http://stackoverflow.com/questions/18791212, combination of that post, `rev()` and `sapply()` should do the trick. – zx8754 Jul 18 '16 at 07:39
  • @zx8754 I know that combination of something will do the trick :-) – 989 Jul 18 '16 at 07:55

2 Answers2

3

How about this?

v <- c(2, 4, 6, 8)

First create a matrix with alternating directions of v. Because matrices are filled column-wise we have to transpose in the end.

m <- matrix(0, length(v), length(v) + 1)
m[, c(FALSE, TRUE)] <- rev(v)
m[, c(TRUE, FALSE)] <- v

m <- t(m)

Now create the zero anti-diagonal by filling the upper and lower triangles and then reversing the columns:

m1 <- matrix(0, length(v) + 1, length(v) + 1)
m1[upper.tri(m1)] <- m[upper.tri(m, TRUE)]
m1[lower.tri(m1)] <- m[lower.tri(m)]
m1[, rev(seq_len(ncol(m1)))]

#     [,1] [,2] [,3] [,4] [,5]
#[1,]    8    6    4    2    0
#[2,]    2    4    6    0    8
#[3,]    8    6    0    4    2
#[4,]    2    0    4    6    8
#[5,]    0    8    6    4    2

I expect this to be an efficient solution for vectors of a larger size. For small vectors loop-based solutions are possibly faster.

Roland
  • 127,288
  • 10
  • 191
  • 288
0

Here is a better way to go around this:

rv <- rev(v)
f <- function(vec, pos){z<-rep(NA,length(vec)+1);z[pos]<-0;z[is.na(z)]<-vec;z;}

t(sapply(5:1, function(x) {if (x%%2==1) f(rv,x) else f(v,x)}))

     # [,1] [,2] [,3] [,4] [,5]
# [1,]    8    6    4    2    0
# [2,]    2    4    6    0    8
# [3,]    8    6    0    4    2
# [4,]    2    0    4    6    8
# [5,]    0    8    6    4    2

Function f, inserts 0 into vec at the specified position pos.

BENCHMARKING

library(microbenchmark)
v <- c(2, 4, 6, 8)
rv <- rev(v)
f <- function(vec, pos){z<-rep(NA,length(vec)+1);z[pos]<-0;z[is.na(z)]<-vec;z;}
f_m0h3n <- function(v){t(sapply(5:1, function(x) {if (x%%2==1) f(rv,x) else f(v,x)}))}
f_Roland <- function(v){
   m <- matrix(0, length(v), length(v) + 1)
   m[, c(FALSE, TRUE)] <- rev(v)
   m[, c(TRUE, FALSE)] <- v
   m <- t(m)
   m1 <- matrix(0, length(v) + 1, length(v) + 1)
   m1[upper.tri(m1)] <- m[upper.tri(m, TRUE)]
   m1[lower.tri(m1)] <- m[lower.tri(m)]
   m1[, rev(seq_len(ncol(m1)))]
}

all(f_m0h3n(v)==f_Roland(v))
# [1] TRUE

microbenchmark(f_m0h3n(v), f_Roland(v))

# Unit: microseconds
        # expr     min       lq     mean  median       uq     max neval
  # f_m0h3n(v) 106.931 109.4975 115.1818 112.064 119.7625 180.927   100
 # f_Roland(v) 114.202 116.3410 128.5183 119.763 126.8210 430.290   100
989
  • 12,579
  • 5
  • 31
  • 53
  • @DavidArenburg Simplicity, clarity and conciseness. – 989 Jul 23 '16 at 22:00
  • This is a very small matrix to bench on. This is exactly what Roland said "*I expect this to be an efficient solution for vectors of a larger size. For small vectors loop-based solutions are possibly faster.*". If you want to benchmark, you will need a bigger matrix – David Arenburg Jul 24 '16 at 03:44
  • @DavidArenburg generating this matrix is what the OP is asked for. Nothing is said about the scalability. Btw, let's finish this commenting. You think this answer isn't even good, I'm OK! – 989 Jul 24 '16 at 09:50
  • I have nothing special against this answer. I'm just against putting arbitrary concepts into SO answers. This is a public information- not your personal notebook. If you are going to make certain claims- it is better to back them up by facts or at least explain what you mean. – David Arenburg Jul 24 '16 at 09:56
  • @DavidArenburg It's backed by benchmarking. You think its not enough, I'm OK! – 989 Jul 24 '16 at 10:13