user11057680
user11057680

Reputation: 105

replacing specific positional value in each matrix within a list, with sequential values from a vector in r

I am attempting to replace a specific value in my list of matrices with each sequential value in a vector called one.to.two.s. This vector comprises a sequence of numbers running from 0.4 to 0.89 with steps of 0.01. From the code below, I would like to replace the value 2 in all matrices in the list by each consecutive value of one.to.two.s: the value 2 in the first matrix is replaced by the first value of one.to.two.s, the value 2 in the second matrix is replaced by the second value of one.to.two.s and so forth.

As an extension, I would like to be able repeat the one.to.two.s sequence if the vector had say length 50 and the list was say length 100. Below, I have a for loop which doesn't work, but I believe this could be handled with lapply somehow.

 A <- lapply(1:50, function(x)  # construct list of matrices
    matrix(c(0, 0, 0, 0,
             2, 0, 0, 0,
             0, 0, 0, 0,
             0, 0, 0, 1), nrow = 4,ncol=4, byrow = TRUE))
  Anew <-A

  one.to.two.s <- c(seq(from = 0.40, to = 0.89,by=0.01))
  
  for(t in 1:length(Anew)) {
    Anew[[t]][2,1] <- one.to.two.s
  }

Upvotes: 0

Views: 50

Answers (4)

Dion Groothof
Dion Groothof

Reputation: 1456

I believe this is what you are looking for. In this example, the list consists of 105 matrices.

# use replicate() instead of lapply()
B <- 50L
A <- replicate(B*2.1,
               matrix(c(0, 0, 0, 0,
                        2, 0, 0, 0,
                        0, 0, 0, 0,
                        0, 0, 0, 1), nrow = 4,ncol=4, byrow = TRUE),
               simplify = FALSE)
Anew <- A
one.to.two.s <- seq(from = 0.40, to = 0.89, by = 0.01)

# loop over all elements in Anew
for (t in seq_along(Anew)) {
  Anew[[t]][2,1] <- one.to.two.s[
    seq_len(length(Anew) + 2L) %% (length(one.to.two.s) + 1L)
  ][t]
}

# > head(sapply(Anew, '[', 2))
# [1] 0.40 0.41 0.42 0.43 0.44 0.45

# > tail(sapply(Anew, '[', 2))
# [1] 0.89 0.40 0.41 0.42 0.43 0.44

Upvotes: 0

IceCreamToucan
IceCreamToucan

Reputation: 28695

Using an example one.to.two.s which is shorter than length(A), you could use rep with length.out to make it the correct length, and then Map over that vector and A to create Anew

one.to.two.s <- seq(from = 0.4, to = 0.8, by = 0.01)

Anew <- Map(function(A, x) {
  A[2, 1] <- x
  A
}, A, rep(one.to.two.s, length.out = length(A)))

Created on 2022-01-27 by the reprex package (v2.0.1)

Upvotes: 1

user11057680
user11057680

Reputation: 105

I forgot to add [t] to the end of my replacement as well. Also can repeat a vector ahead of time.

for(t in 1:length(Anew)) {
    Anew[[t]][2,1] <- one.to.two.s
  }

instead becomes

for(t in 1:length(Anew)) {
    Anew[[t]][2,1] <- one.to.two.s[t]
  }

Upvotes: 0

ThomasIsCoding
ThomasIsCoding

Reputation: 102251

You can try the following for loop if you have longer list than the vector

for(t in 1:length(Anew)) {
    Anew[[t]][2,1] <- one.to.two.s[(t-1)%%length(one.to.two.s)+1]
  }

Upvotes: 0

Related Questions