dww
dww

Reputation: 31452

Re-order vector row-wise from top of vector

Suppose I have a vector (x) whose values are in such an order that if they were in an nx by ny matrix, the matrix would contain values that increase by row starting from the bottom left upwards. Any remaining unfilled values in the matrix will then be NA. Let me illustrate with an example:

nr=3
nc=3    
mx = matrix(c(7,NA,NA,4:6,1:3), nr, nc, byrow = T)
#      [,1] [,2] [,3]
# [1,]    7   NA   NA
# [2,]    4    5    6
# [3,]    1    2    3
x = c(mx)
# [1]  7  4  1 NA  5  2 NA  6  3

Now, I would like to re-order x into a new vector (y) such that if the values of y were in a matrix the NAs would remain in the same location, but the other values would be ordered increasing row-wise from the top left. I.e. y should look like this

my = matrix(c(1,NA,NA,2:4,5:7), nr, nc, byrow = T)
#      [,1] [,2] [,3]
# [1,]    1   NA   NA
# [2,]    2    3    4
# [3,]    5    6    7
y = c(y)
# [1]  1  2  5 NA  3  6 NA  4  7

I want to find a vector of indices that maps x to y. In this case it would be

indices = c(3, 6, 5, 4, 9, 8, 7, 2, 1)
identical(x[indices], y)
#TRUE

But, I'm struggling to find a simple algorithm that can generate indices for any values of nr, nc, and any number of NA values in x. Any suggestions? NB, we can assume that there will never be enough NAs to fill an entire matrix row

Upvotes: 1

Views: 57

Answers (2)

d.b
d.b

Reputation: 32548

my = t(replace(t(mx), which(!is.na(t(mx))), sort(mx)))
my
#     [,1] [,2] [,3]
#[1,]    1   NA   NA
#[2,]    2    3    4
#[3,]    5    6    7
match(my, mx)
#[1] 3 6 5 4 9 8 4 2 1

Or, if the indices vector must have a one-to-one correspondence between the two vectors, such that it does not point to the same NA twice:

match(replace(my, is.na(my), paste0("NA", seq(sum(is.na(my))))),
      replace(mx, is.na(mx), paste0("NA", seq(sum(is.na(mx))))))
#[1] 3 6 5 4 9 8 7 2 1

Upvotes: 3

IRTFM
IRTFM

Reputation: 263332

If you use apply rowwise, and then transpose, you get back the original matrix arrangement. The function given to apoply replaces non-NA values with ordered non-NA values and then returns the full row..

t( apply(mx, 1, function(x){ x[!is.na(x)] <- x[!is.na(x)][order(x[!is.na(x)])]; x}) )
     [,1] [,2] [,3]
[1,]    7   NA   NA
[2,]    4    5    6
[3,]    1    2    3

If you wanted the values without the matrix arrangement just unclass or wrap it in c. If you want the order vector then you could first set a y value inside the function that is 1:length(x) and then assign the !is.na ordering.

Upvotes: 0

Related Questions