更改具有重复名称的 R 向量中的多个元素

Change multiple elements in R vector with repeated names

假设我有一个名称重复的向量:

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

我想查找和更改命名元素。如果我定义

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

ChangeTo <- c(9,8,7)

我想将所有名为 'a' 的元素更改为 9 所有名为 'b' 的元素都更改为 8 等。如果我这样做:

x[ElementsToChange] <- ChangeTo

这只会改变第一个(而不是所有)元素。

如何以简单而优雅的方式更改所有内容?

命名元素在名称唯一时效果更好,但您可以这样做

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 中使用适当的 key/values 会更容易。

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)

我假设您不需要保留任何匹配项,这使得它不太优雅:

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

如果您想要恢复名称,则必须重命名向量。

另一个直接替换为<-的选项,归功于@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

中的匹配元素
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 

您可以使用一个 split* 命令来完成:

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

这首先按名称拆分 x 向量,然后对属于 ElementsToChange 向量的所有元素进行子集化,并将这些值替换为 ChangeTo 值。

* 从技术上讲,您在这里使用 split<-,即对拆分数据进行赋值。原始向量之后保持其结构。

您可以使用此函数并提供您的 elementsToChange 和 changeTo 向量来获取已更改的列表。

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)
}