Changing multiple elements in a duplicate R-vector

Say I have a vector with duplicate names:

x <- c(a=1, b=2, a=3, c=4, c=5, b=1, d=1)

I want to search and modify named elements. If I define

ElementsToChange <- c("a","b","c")

ChangeTo <- c(9,8,7)

I want to change all elements named "a" to 9 of all those named "b" by 8, etc., if I do this:

x[ElementsToChange] <- ChangeTo

This will change only the first (and not all) elements.

How can I change everything in a simple and elegant way?

+6
source share
6 answers

You can do this using one command split*:

split(x, names(x))[ElementsToChange] <- ChangeTo
#x
#a b a c c b d 
#9 8 9 7 7 8 1 

This first splits the vector x into its names, then multiplies all the elements that are part of the vector ElementsToChange, and replaces these values ​​with values ChangeTo.

* , split<- , .. . .

+10

, , :

ifelse(names(x)%in%ElementsToChange,ChangeTo[match(names(x),ElementsToChange)],x)
[1] 9 8 9 7 7 8 1

, , .

+4

, , -

Reduce(function(x, z) {
  x[names(x)==z$k] <- z$v
  x
}, split(data.frame(k=ElementsToChange, v=ChangeTo), seq_along(ChangeTo)), init=x)
# a b a c c b d 
# 9 8 9 7 7 8 1

/ data.frame.

library(tidyverse)
dd <- data_frame(k=names(x), v=x)
tt <- data_frame(k=ElementsToChange, newv=ChangeTo)
dd %>% left_join(tt) %>% mutate(v=coalesce(newv, v), newv=NULL)
+3

, <-, @Frank:

m <- match(names(x), ElementsToChange)
x[!is.na(m)] <- ChangeTo[na.omit(m)]

x
a b a c c b d 
9 8 9 7 7 8 1 

, . x ElementsToChange, ChangeTo

+3
ids = match(names(x), ElementsToChange)
replace(x, which(!is.na(ids)), ChangeTo[ids[!is.na(ids)]])
#a b a c c b d 
#9 8 9 7 7 8 1 
+2

You can use this function and provide your ToChange and changeTo vectors to get a modified list.

library(dplyr)

change <- function(x, elementsToChange = c("a"), changeTo=c(5)){

  if(length(elementsToChange)!=length(changeTo)) {stop("length of elementsToChange is not equal to changeTo")}
  temp<- tibble(name = names(x), value = x)
  temp.change<- tibble(name = elementsToChange, value = changeTo)
  temp2<-temp%>%left_join(temp.change, by = "name")
  temp2<-within(temp2, {
    value.y[is.na(value.y)]<- value.x[is.na(value.y)]
  })
  ret<-temp2$value.y
  names(ret)<-temp2$name
  return(ret)
}
0
source

All Articles