我有一个测试df:
testdf<-data.frame(x = seq(1,10), y= c(1, 1, 4, 3, 2, 6, 7, 4, 9, 10))
testdf
x y
1 1 1
2 2 1
3 3 4
4 4 3
5 5 2
6 6 6
7 7 7
8 8 4
9 9 9
10 10 10
我想编写一个输入行号的函数,然后“跟随”y值,直到找到列x =列y的行。
get_acc_x<-function(rownum){
if(testdf[rownum, 'x'] == testdf[rownum, 'y']){
return(rownum)
}else{
get_acc_x(testdf[rownum, 'y'])
}
}
因此,运行get_acc_x(1)返回1,get_acc_x(9)返回9,get_acc_x(2)返回1,get_acc_x(5)也返回1,等等。
但是,如果我在数字8上运行此函数,它将进入无限循环,在3和4之间来回。在这种情况下检测无限循环的最简单方法是什么?我想跟踪过去的输入,所以如果不止一次使用相同的输入,我可以停止该功能,但我不知道如何最好地跟踪输入。
答案 0 :(得分:3)
您可以传入一个标记已访问行的参数:
get_acc_x<-function(rownum, seen){
if (seen[rownum]) {
# Whatever you want to do, cycle detected
}
seen[rownum] <- T
if(testdf[rownum, 'x'] == testdf[rownum, 'y']){
return(rownum)
}else{
get_acc_x(testdf[rownum, 'y'], seen)
}
}
致电时,请使用get_acc_x(rownum, rep(F, nrow(df))
传递全部False
参数。
答案 1 :(得分:2)
如果您不想明确传递受访节点,可以使用sys.frames
从调用堆栈中读取它们。如果你认为递归会相当浅,那么就不应该对性能产生太大影响,并且由于它没有改变签名,你不必修改任何调用代码。
get_acc_x2<-function(rownum){
if(testdf[rownum, 'x'] == testdf[rownum, 'y']){
return(rownum)
}else{
rownum %in% sapply(head(sys.frames(), -1), `[[`, "rownum") &&
stop('infinite recursion detected')
get_acc_x2(testdf[rownum, 'y'])
}
}
示例:
> get_acc_x2(8)
Error in get_acc_x2(8) : infinite recursion detected
答案 2 :(得分:1)
您需要将之前看到的值作为参数传递。我添加了一个包装函数来处理传递初始空向量。
x <- c(1,2,3,4,5,6,7,8,9,10)
y <- c(1,1,4,3,2,6,7,4,9,10)
df <- data.frame(x,y)
get_acc_x <- function(rownum,df) get_acc_x_rec(rownum,df,numeric())
get_acc_x_rec<-function(rownum,df,prev){
if(df[rownum, 'x'] == df[rownum, 'y']){
return(rownum)
}else{
if(is.element(df[rownum, 'y'],prev)) get_acc_x(df[rownum, 'y'],df,c(prev,rownum))
else stop("Damnit!")
}
}