使用R

时间:2019-07-10 13:22:46

标签: r recursion

我的数据框只有4列:RoadName,Product,Source和Destination,它表示将产品从point1移到point2的一种方式(RoadName)。 但是,point1和point2不一定是“初始点”或“最终目的地”。一个寄存器中的目标可以是另一寄存器中的源。我需要为每种产品列出从第一个点到最后一个点的所有完整可能路径。 我定义的第一点是我找不到的目的地。因此,对于他们的每个目的地,我检查它是否是另一个目的地的来源,如果为真,则检查该目的地是否是另一个目的地的来源.....依此类推... 不同的源可以具有相同的目的地,更难的是,经过几个步骤,以前的源再次成为了目的地。例如,我的数据框具有以下寄存器:

Case  RoadName   Product     Source     Dest
99999   R1         Prod1     Point1     Point2
99999   R2         Prod1     Point2     Point3
99999   R3         Prod1     Point2     Point4
99999   R4         Prod1     Point3     Point4
99999   R5         Prod1     Point3     Point2

这意味着:Point1发送到Point2,后者可以发送到Point3和Point4。 Point3再次发送到Point4和Point2(是否使用其他RoadName)。这将导致无限循环,对吧?)

对于这个小例子,我想结束以下几行(源代码中的“ dbPathWay”):

Case    Prod      1          2         3       4
99999   Prod1   Point1    Point2    Point3    Point4
99999   Prod1   Point1    Point2    Point3    Point2
99999   Prod1   Point1    Point2    Point4

我不需要显示RoadName,但可以使用它。

我试图解决在R中使用递归函数的问题,但是我在这段时间过得很不好。我已使用this link作为构建算法的参考(在此示例中,最终目标是一个参数。我不知道我的最终目标。当源没有目标时,我会中断搜索)。 但是,在我的代码中,dbPathWay返回空,并且我无法在函数内部进行调试以了解正在发生的情况。

主要脚本只是产品中的一个循环。为了避免使用大代码,我仅以一种情况和产品为例

require("dplyr")
require("plyr")

dbProdDest <- data.frame(Case=c(99999,99999,99999,99999,99999), RoadName = c("R1", "R2", "R3", "R4", "R5"), Product=c("Prod1","Prod1","Prod1","Prod1","Prod1"), Source = c("Point1","Point2","Point2","Point3","Point3"), Dest=c("Point2","Point3","Point4","Point4","Point1"))

dbPathWay <- data.frame()
dbPathWay <- NULL  #data frame to save all possible paths. Repre
dbProdDest <- data.frame()

#Find sources that are not destinations (initial points)
dbSources <-  (dbProdDest[!(dbProdDest$Source %in% dbProdDest$Dest),])

for (iSource in unique(dbSources$Sources)){

 # Initialize a list to be used to append every step on the pathway
  newRowPathWay <- list("Case" = 99999, "Product" = "Prod1")

  iNewSource <- iSource
  #Recursive part
   GetDestinRecursive(dbProdDest, iNewSource, newRowPathWay, dbPathWay)

} # end  

尽管递归函数应该接收产品的源和原始数据帧以及所有源目标。对于具有源的那些目的地,将newRowPathWay列表与目的地名称一起递增,并调用递归。对于每个目的地,我必须检查它是否已经是来源,在这种情况下,我将其视为最终目的地(在示例中,Point1为4)。对于那些不是新来源的目标,newRowPathWay与数据框dbPathWay绑定。


GetDestinRecursive <- function(dbProdDest, iNewSource,  newRowPathWay, dbPathWay){
  countDest <- as.character(length(newRowRoteiro)-1)
  newRowPathWay[[countDest]] <- iNewSource

  dbNewDest <- dbProdDest[dbProdDest$Source == iNewSource,]

  #If there is no new destinations to iNewSource, so iNewSource is an end
  if (is.null(dbNewDest) ){
    #Append RowPathWay in dbPathWaty
    dfRow <- data.frame(matrix(unlist(newRowPathWay), ncol = length(newRowPathWay), byrow=F),stringsAsFactors=FALSE)
    dbPathWay <- rbind.fill(dbPathWay , dfRow )
    return(dbPathWay)
  } else{
    #For each new destination, check if it is already a vertice in the pathway. If it is true, break the loop. Otherwise, call recursion
    for (iDest in dbNewDest$Dest){
      if (iDest %in% newRowPathWay){
        dfRow <- data.frame(matrix(unlist(newRowPathWay), ncol = length(newRowPathWay), byrow=F),stringsAsFactors=FALSE)
        dbPathWay <- rbind.fill(dbPathWay , dfRow )  
        return(dbPathWay )
      } else
      {
        return(GetDestinRecursive(dbProdDest, iDest, newRowPathWay, dbPathWay ))
      } #end if iDest
    } # end for iDest
  } # end if is.null

} #end GetDestinRecursive

我感谢使该递归函数起作用和/或对其进行调试的任何帮助(我在代码开始时尝试使用browser(),但是它不起作用,我也尝试单击“源”按钮,但它没有在循环内进行逐步调试)

1 个答案:

答案 0 :(得分:1)

首先,仅检查一下:您是否通过产品进行了外部循环,以确保dbProdDest仅容纳1个产品?这是必需的,因为Point1并非Prod1的目的地,但可以是Prod2的目的地。

我更改了代码以处理您提供的示例,但尚未全面测试

我对代码进行的更改:

  1. 示例数据框dbProdDest。如您所给出的示例,最后的目标值已从Point1更改为Point2。否则,没有没有目的地的来源。 这可能是browser()无法正常工作的原因。它从未发挥作用。

  2. 我删除了行:

    dbPathWay <- NULL  #data frame to save all possible paths
    dbProdDest <- data.frame()
    

dbPathWay在之前定义为data.frame,而另一个清除了示例数据

所以第一部分看起来像这样:

dbProdDest <- data.frame(Case=c(99999,99999,99999,99999,99999), RoadName = c("R1", "R2", "R3", "R4", "R5"), Product=c("Prod1","Prod1","Prod1","Prod1","Prod1"), Source = c("Point1","Point2","Point2","Point3","Point3"), Dest=c("Point2","Point3","Point4","Point4","Point2"))

dbPathWay <- data.frame()
# dbPathWay <- NULL  #data frame to save all possible paths. Repre
# dbProdDest <- data.frame()

#Find sources that are not destinations (initial points)
dbSources <-  (dbProdDest[!(dbProdDest$Source %in% dbProdDest$Dest),])

for (iSource in unique(dbSources$Source)){

    # Initialize a list to be used to append every step on the pathway
    newRowPathWay <- list("Case" = 99999, "Product" = "Prod1")

    iNewSource <- iSource
    #Recursive part
    dbPathWay <- GetDestinRecursive(dbProdDest, iNewSource, newRowPathWay, dbPathWay)

} # end 
  1. if(is.null(dbNewDest))更改为if(nrow(dbNewDest)== 0)

  2. 递归函数返回新的dbPathWay-我确保它在调用环境中已更新。代码:

    GetDestinRecursive <- function(dbProdDest, iNewSource,  newRowPathWay, dbPathWay){
        countDest <- as.character(length(newRowPathWay)-1)
        newRowPathWay[[countDest]] <- iNewSource
    
        dbNewDest <- dbProdDest[dbProdDest$Source == iNewSource,]
    
        #If there is no new destinations to iNewSource, so iNewSource is an end
        if (nrow(dbNewDest) == 0){
            #Append RowPathWay in dbPathWaty
            dfRow <- data.frame(matrix(unlist(newRowPathWay), ncol = length(newRowPathWay), byrow=F),stringsAsFactors=FALSE)
            dbPathWay <- rbind.fill(dbPathWay , dfRow )
            return(dbPathWay)
        } else{
            #For each new destination, check if it is already a vertice in the pathway. If it is true, break the loop. Otherwise, call recursion
            for (iDest in dbNewDest$Dest){
                if (iDest %in% newRowPathWay){
                    dfRow <- data.frame(matrix(unlist(newRowPathWay), ncol = length(newRowPathWay), byrow=F),stringsAsFactors=FALSE)
                    dbPathWay <- rbind.fill(dbPathWay , dfRow )  
                } else
                {
                    dbPathWay <- GetDestinRecursive(dbProdDest, iDest, newRowPathWay, dbPathWay )
                } #end if iDest
            } # end for iDest
        } # end if is.null
        return(dbPathWay )
    } #end GetDestinRecursive
    

另一种选择是仅省略dbPathWay参数,并使用<<-运算符填充表:

GetDestinRecursive2 <- function(dbProdDest, iNewSource,  newRowPathWay){
    countDest <- as.character(length(newRowPathWay)-1)
    newRowPathWay[[countDest]] <- iNewSource

    dbNewDest <- dbProdDest[dbProdDest$Source == iNewSource,]

    #If there is no new destinations to iNewSource, so iNewSource is an end
    if (nrow(dbNewDest) == 0){
        #Append RowPathWay in dbPathWaty
        dfRow <- data.frame(matrix(unlist(newRowPathWay), ncol = length(newRowPathWay), byrow=F),stringsAsFactors=FALSE)
        dbPathWay <<- rbind.fill(dbPathWay , dfRow )
        # return(dbPathWay)
    } else{
        #For each new destination, check if it is already a vertice in the pathway. If it is true, break the loop. Otherwise, call recursion
        for (iDest in dbNewDest$Dest){
            if (iDest %in% newRowPathWay){
                dfRow <- data.frame(matrix(unlist(newRowPathWay), ncol = length(newRowPathWay), byrow=F),stringsAsFactors=FALSE)
                dbPathWay <<- rbind.fill(dbPathWay , dfRow )  
                # return(dbPathWay )
            } else
            {
                GetDestinRecursive2(dbProdDest, iDest, newRowPathWay )
            } #end if iDest
        } # end for iDest
    } # end if is.null

} #end GetDestinRecursive

在这种情况下,请确保未将递归函数的返回值分配给dbPathWay,因此以这种方式调用

#Recursive part
GetDestinRecursive2(dbProdDest, iNewSource, newRowPathWay)