更改具有重复名称的 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)
}
假设我有一个名称重复的向量:
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)
}