简体   繁体   中英

Dplyr replace list of elements

I made a better reprex based on your suggestions. In case of repeated lines, the approaches based on rows_update and match seem to fail, whereas those based on join are robust. Since I will need this a lot, I wrote an ugly function. If anyone can to this better, please be my guest. Otherwise I will accept the answer by Duck.

Please consider the following tibbles df and df2

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

join_replace <- function(val_ini, x, val_new, x2 ){

    require(magrittr)
    
    df1 <- tibble(value=val_ini, x_pos=x)
    df2 <- tibble(value_new=val_new, x_pos=x2)

    df_out <- df1 %>%
        left_join(y=df2) %>%
        mutate(value_new=if_else(is.na(value_new), value, value_new)) %$%
        value_new %>% as.vector

    
}





df <- tibble(x=seq(10), y=letters[seq(10)])

df <- bind_rows(df,df)

df
#> # A tibble: 20 x 2
#>        x y    
#>    <int> <chr>
#>  1     1 a    
#>  2     2 b    
#>  3     3 c    
#>  4     4 d    
#>  5     5 e    
#>  6     6 f    
#>  7     7 g    
#>  8     8 h    
#>  9     9 i    
#> 10    10 j    
#> 11     1 a    
#> 12     2 b    
#> 13     3 c    
#> 14     4 d    
#> 15     5 e    
#> 16     6 f    
#> 17     7 g    
#> 18     8 h    
#> 19     9 i    
#> 20    10 j


df2 <- tibble(x=c(2,3,5), y=c("kk", "xx", "zz"))


df2
#> # A tibble: 3 x 2
#>       x y    
#>   <dbl> <chr>
#> 1     2 kk   
#> 2     3 xx   
#> 3     5 zz





df_out <- df %>% left_join(df2 %>% rename(y1=y)) %>%
  mutate(y=ifelse(!is.na(y1),y1,y)) %>% select(-y1)
#> Joining, by = "x"

df_out
#> # A tibble: 20 x 2
#>        x y    
#>    <dbl> <chr>
#>  1     1 a    
#>  2     2 kk   
#>  3     3 xx   
#>  4     4 d    
#>  5     5 zz   
#>  6     6 f    
#>  7     7 g    
#>  8     8 h    
#>  9     9 i    
#> 10    10 j    
#> 11     1 a    
#> 12     2 kk   
#> 13     3 xx   
#> 14     4 d    
#> 15     5 zz   
#> 16     6 f    
#> 17     7 g    
#> 18     8 h    
#> 19     9 i    
#> 20    10 j

df_out2 <- df %>%
    mutate(y=join_replace(y, x, df2$y, df2$x))
#> Loading required package: magrittr
#> Joining, by = "x_pos"

df_out2
#> # A tibble: 20 x 2
#>        x y    
#>    <int> <chr>
#>  1     1 a    
#>  2     2 kk   
#>  3     3 xx   
#>  4     4 d    
#>  5     5 zz   
#>  6     6 f    
#>  7     7 g    
#>  8     8 h    
#>  9     9 i    
#> 10    10 j    
#> 11     1 a    
#> 12     2 kk   
#> 13     3 xx   
#> 14     4 d    
#> 15     5 zz   
#> 16     6 f    
#> 17     7 g    
#> 18     8 h    
#> 19     9 i    
#> 20    10 j

Created on 2020-10-06 by the reprex package (v0.3.0.9001)

I am trying to achieve something simple: for every x element in df also present in df2, change the value of y in df to the corresponding y value in df2.

I can achieve this with map or other rather cumbersome strategies, but perhaps someone can suggest something simpler?

Thanks!

You can try an approach with left_join() and a conditional:

library(dplyr)
#Code
df <- df %>% left_join(df2 %>% rename(y1=y)) %>%
  mutate(y=ifelse(!is.na(y1),y1,y)) %>% select(-y1)

Output:

# A tibble: 10 x 2
       x y    
   <dbl> <chr>
 1     1 a    
 2     2 kk   
 3     3 xx   
 4     4 d    
 5     5 zz   
 6     6 f    
 7     7 g    
 8     8 h    
 9     9 i    
10    10 j    

对于dplyr方式,您可以执行以下操作:

df %>% rows_update(df2, by = "x")

What about joining it?

df<-df %>% 
  left_join(df2,by="x") %>% 
  drop_na() %>% 
  dplyr::select(x,y.y) %>% 
  rename("y"="y.y")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM