如何将循环结构更改为sapply函数?

时间:2013-11-27 11:29:24

标签: r

我已将for循环更改为sapply函数,但失败了 我想知道为什么?

list.files("c:/",pattern="mp3$",recursive=TRUE,full.names=TRUE)->z    
c()->w   
left<-basename(z)    
for (i in 1:length(z)){    
if (is.element(basename(z[i]),left))    
{     
   append(w,values=z[i])->w;    
   setdiff(left,basename(z[i]))->left    
   }}   
print(w) 



list.files("c:/",pattern="mp3$",recursive=TRUE,full.names=TRUE)->z    
c()->w    
left<-basename(z)    
sapply(z,function(y){    
if (is.element(basename(y),left))    
{  append(w,values=y)->w;    
   setdiff(left,basename(y))->left    
   }})    
print(w)

我选择音乐的规则是,如果基本名称(音乐)相同,则只保存一个full.name音乐,因此unique不能直接使用。有两个概念full.name和文件路径中的basename可能会使人们感到困惑。

1 个答案:

答案 0 :(得分:1)

你遇到的问题是你希望你的功能有两个副作用。副作用是指修改其范围之外的对象:wleft

当然,wleft只在函数范围内被修改,然后它们最终会在函数调用结束时丢失。

相反,您希望在功能环境之外修改wleft。为此,您可以使用<<-代替<-

sapply(z, function(y) {    
  if (is.element(basename(y),left)) {
    w <<- append(w, values = y)    
    left <<- setdiff(left, basename(y))   
  }
})

请注意,我一直在说“你想要”,“你可以”,但这不是“你应该”做的。具有副作用的函数实际上被认为是错误的编程。试着阅读它。

此外,最好将*apply工具保留给可以独立运行其输入的函数。相反,你有一个算法,迭代的结果取决于前一个的结果。在这些情况下,您最好使用for循环,除非您可以在更适合*apply的框架中重新考虑算法,或者可以使用可以处理此类依赖情况的函数:{{ 1}},filterunique

例如,使用rle,您的代码可以重写为:

unique

它还有一个优点,就是它不会递归地构建一个对象,这是当前代码的另一个禁忌。