Replacing values in column X with values from column Y, but only if the values of X match the values in column Z

I have two data frames, one with 1 column (X), and the other with 2 columns (Y & Z):

Column X contains numbers 1:99, but occasionally has some letters instead of numbers, ie: 1, 2, 3, A, 5, B, 7, 8, C, D, 11, 12 etc.

Column Y contains these same letters, which are paired (as appearing in column Z) to certain numbers, ie:

A 4

B 6

C 9

D 10

How can I replace the letters in column X with the values of column Z, according to whether the letters in column X match with the letters in column Y? This would result in column X being 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 etc.

A straightforward merge won't work (I need to retain all values in X) and I'm not sure how I can use sub conditionally. Also, column Y and Z contain more rows than needed for column X, so I can't just use cbind. I'm not very skilled at using regex, although that is probably my best bet...

Any help would be greatly appreciated!


I'd just use a for loop. Creating your data:

df1 <- data.frame(X = c("A", 5, "B", 7, 8, "C", "D", 11, 12))
df2 <- data.frame(Y = c("A", "B", "C", "D"),
                  Z = c(4, 6, 9, 10))

We need to make sure things are character vectors, not factors, for testing equality

df1$X <- as.character(df1$X)
df2$Y <- as.character(df2$Y)

Then we can do the replacing:

for (i in 1:nrow(df2)) {
    df1$X[df1$X == df2$Y[i]] <- as.character(df2$Z[i])

Finally, I'm guessing you want the X as numeric now that all the letters are gone:

df1$X <- as.numeric(df1$X)

How about X[X==Y] <- Z[X==Y] ? Or, calling your Y,Z dataframe DF ,

X[X==DF$Y] <- DF$Z[X==DF$Y]

Edit: this is essentially the same as Shuja's answer, but there's no need for a loop so far as I can see.

Need Your Help