簡體   English   中英

檢測遞歸函數中的無限循環(R)

[英]Detecting an infinite loop in a recursive function (R)

我有一個測試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之間來回。在這種情況下檢測無限循環的最簡單方法是什么? 我想跟蹤過去的輸入,所以如果不止一次使用相同的輸入,我可以停止該功能,但我不知道如何最好地跟蹤輸入。

您可以傳入一個標記訪問行的參數:

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參數。

如果您不想顯式傳遞sys.frames節點,可以使用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

您需要將先前看到的值作為參數傳遞。 我添加了一個包裝函數來處理傳遞初始空向量。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM