fkliron
fkliron

Reputation: 103

match names between vectors and assign corresponding values

This is a problem about efficiency in R. I have two numerical vectors with names attributes, and I want to efficiently assign the values of one vector to the other based on the common names.

For example, the first vector is defined as:

set.seed(1);
a<-rep(NA,10);
names(a)<-1:10;
d<-a;  #  we will need this later 
a

 1  2  3  4  5  6  7  8  9 10 
NA NA NA NA NA NA NA NA NA NA

and the second vector is defined as:

b<-sample(letters, 5);
names(b)<-sample(1:10, 5);
b

9  10   6   5   1 
"g" "j" "n" "u" "e" 

now the following code does exactly what I want, it looks for all names(b) that are common with names(a) and assigns to those places in a the values of b:

for(p in 1:length(b)){
    a[which(names(a) == names(b)[p])]<-b[p]
};

a

1   2   3   4   5   6   7   8   9  10 
"e"  NA  NA  NA "u" "n"  NA  NA "g" "j" 

My question is: is there a better more efficient way of doing this? I am dealing with much larger vectors and I keep thinking that there must be a better way of doing this.

A more sophisticated method like:

d[which(names(d) %in% names(b))]<- b
d

1   2   3   4   5   6   7   8   9  10 
"g"  NA  NA  NA "j" "n"  NA  NA "u" "e"  

all.equal(a,d)

[1] "4 string mismatches"

produces wrong results because it requires that names(b) and names(a) are ordered first, which also does not seem to be an optimal strategy.

Any ideas would be greatly appreciated!

Upvotes: 4

Views: 3680

Answers (5)

yatici
yatici

Reputation: 577

1 liner for you:

a[as.integer(names(b))]<-b

Upvotes: 0

joran
joran

Reputation: 173547

I would probably just do this:

a[names(b)] <- b
> a
#   1   2   3   4   5   6   7   8   9  10 
# "e"  NA  NA  NA "u" "n"  NA  NA "g" "j" 

If b is not a subset of a, for example:

set.seed(45)
a <- rep(NA, 10)
names(a) <- sample(10)
#  7  3  2  9 10  8  1  5  4  6 
# NA NA NA NA NA NA NA NA NA NA 

b <- sample(letters, 5)
names(b) <- sample(1:15, 5)
#   7  14   2   5   3 
# "j" "w" "h" "k" "z" 

len <- length(a)
a[names(b)] <- b
a[1:len]
#   7   3   2   9  10   8   1   5   4   6 
# "j" "z" "h"  NA  NA  NA  NA "k"  NA  NA 

Upvotes: 1

dayne
dayne

Reputation: 7784

CORRECT ANSWER:

Based on a comment from @flodel

a[match(names(b), names(a))] <- b

OLD ANSWER:

This gets close. It does not preserve the names of a. I am not sure why. You could reassign the names of a after the fact.

a <- b[match(names(a),names(b))]

Upvotes: 4

user1609452
user1609452

Reputation: 4444

a[intersect(names(b), names(a))] <- b[intersect(names(b), names(a))]
> a
  1   2   3   4   5   6   7   8   9  10 
"e"  NA  NA  NA "u" "n"  NA  NA "g" "j" 

Upvotes: 4

Thomas
Thomas

Reputation: 44525

Try this:

a[names(a) %in% names(b)] <- b[names(a[names(a) %in% names(b)])]

Upvotes: 1

Related Questions