R sapply循环替换for循环

R sapply loop to replace for loop

我之前已经成功将for循环切换到sapply循环, 我知道一个事实 (system.time()) 它们更快。

但我的思维仍然以 for 循环的方式工作...

请帮我转换这个 for 循环案例:

names.list <- c("Anna", "Ana", "Albert", "Albort", "Rob", "Robb", "Tommy", "Tommie")
misspell.list <- c("Anna", "Albort", "Robb", "Tommie")
fix.list <- c("Ana", "Albert", "Rob", "Tommy")

for(i in 1:length(fix.list)) {
        names.list[which(names.list == misspell.list[i])] <- fix.list[i]

}

names.list

给一个sapply()

到目前为止,我得到了:

sapply(seq_along(fix.list), function(x)
        names.list[which(names.list == misspell.list[x])]  <- fix.list[x]
)

但它只是 returns 我的原始向量。

谢谢!

编辑 1:

misspell.list 和 fix.list 是由下面的 adist() 自动创建的,原始的 names.list 有 665 个元素。我的 for() 解决方案 returns length(unique(names.list)) = 653 个元素

# will do another sapply() substitution here soon
for(i in 1:(length(names.list)-1)) {
        distancias[i] <- adist(names.list[i], names.list[i+1])
}

# fix list
misspell.list <- names.list[which(distancias < 2)]
fix.list <- names.list[which(distancias < 2) +1]

编辑 2:多亏了你,我现在是 sapply 霸主 我来这里只是为了展示我的另一个 for-sapply 与 adist()

一起使用的替换
nomes <- sort(unique(names.list))
distancias <- rep(10, length(nomes))

#adist() for finding misspelling
sapply(seq_along(nomes), 
       function(x) {
                if(x<length(nomes)) {
                        distancias[x] <<- adist(nomes[x], nomes[x+1])
                        }
        }
       )
# fix list
misspell.list <- names.list[which(distancias < 2)]
fix.list <- names.list[which(distancias < 2) +1]

另一部分你已经知道了,再次感谢!

如果 misspell.listfix.list 之间存在一对一的对应关系,您可以使用 match 函数

来消除循环
names.list[match(misspell.list,names.list)] <- fix.list

names.list
#[1] "Ana"    "Ana"    "Albert" "Albert" "Rob"    "Rob"    "Tommy"  "Tommy"

使用 match 的解决方案要好得多,但就您尝试执行的操作而言,这会奏效。首先,您不需要 which。您还需要使用 <<- 运算符来告诉循环中定义的内部函数使用全局环境而不是它自己的本地环境 - 否则它不会更改 names.list,只会更改其副本。

sapply(seq_along(fix.list), function(x)
  names.list[names.list == misspell.list[x]]  <<- fix.list[x]
)

names.list
[1] "Ana"    "Ana"    "Albert" "Albert" "Rob"    "Rob"    "Tommy"  "Tommy" 

我建议对您的整个设置进行一些小改动。当像您一样使用索引时,您需要确保顺序始终相同。如果你添加或删除一个名字,整个事情就会分崩离析。

使用命名列表和 lapplysapply,您的代码保持动态,您可以将多个拼写错误匹配到一个名称。

misspell.list  <-  list(
  'Anna' = 'Ana',
  'Albort' = 'Albert',
  'Robb' = 'Rob',
  'Tommie' = 'Tommy'
)

names.list <- c("Anna", "Ana", "Albert", "Albort", "Rob", "Robb", "Tommy", "Tommie")


> sapply(names.list,function(x) ifelse(x %in% names(misspell.list),misspell.list[[x]],x))
    Anna      Ana   Albert   Albort      Rob     Robb    Tommy   Tommie 
   "Ana"    "Ana" "Albert" "Albert"    "Rob"    "Rob"  "Tommy"  "Tommy" 

为了说明我的意思,我正在使用 sample 打乱您的 names.list 向量并将其扩展到 20 个名称。这说明顺序和长度没有影响。

sapply(names.list[sample(1:length(names.list),20,replace = T)],function(x) ifelse(x %in% names(misspell.list),misspell.list[[x]],x))
  Albert   Tommie      Rob   Tommie      Rob    Tommy      Ana     Robb   Tommie      Ana   Tommie   Albort      Ana   Albert   Albert   Albort 
"Albert"  "Tommy"    "Rob"  "Tommy"    "Rob"  "Tommy"    "Ana"    "Rob"  "Tommy"    "Ana"  "Tommy" "Albert"    "Ana" "Albert" "Albert" "Albert" 
   Tommy    Tommy    Tommy      Ana 
 "Tommy"  "Tommy"  "Tommy"    "Ana"