2014-10-05 60 views
0

我試圖設置一些感覺應該很簡單的東西,但我找不出解決方案。我寫了一個精簡版的代碼,試圖在此過程中進行解釋。R - 基於年齡的殺戮

基本上,我想創造一羣「孩子」每一代。然後,爲每一代添加1,並在年齡大於3時刪除列表條目。代碼幾乎可行 - 我認爲問題與調用fl的長度然後從列表中刪除行有關,但我不確定。最終結果(fl)如果工作正常,則不應該有大於3的條目。

代碼:

#NUMBER OF PARENTS TO START WITH 
parents <- 10 
#NUMBER OF GENERATIONS TO RUN 
generations <- 5 
#NUMBER OF CHILDREN TO CREATE EACH GENERATION 
children <- 5 
#AGE TO KILL 
death <- 3 

pl <- list() 
cl <- list() 
fl <- list() 
kl <- list() 

#CREATE PARENTS 
for (i2 in 1:parents) { 
pl[[i2]] <- 0 
} 

fl <- pl 


#START GEN LOOP 

i3 <- 0 
while (i3 < generations) { 
i3 <- i3 + 1 


#CREATE CHILDREN 
for (i5 in 1:children) { 
cl[[i5]] <- 0 
} 

#ADD CHILDREN TO FINAL LIST 
fl <- c(fl, cl) 

#ADD 1 TO AGE 
for (i6 in 1:length(fl)) { 
fl[[i6]] <- fl[[i6]] + 1 
} 


###PROBLEM### 
#KILL BASED ON AGE 
i4 <- 0 
while (i4 < length(fl)) { 
i4 <- i4 + 1 
if (fl[[i4]] > death) { 

#ADD TO KILL LIST FOR DEBUGGING 
kl <- c(kl, fl[[i4]]) 

#REMOVE FROM fl 
fl <- fl[-c(i4), drop=FALSE] 
} 
} 

#CLOSE GEN LOOP 
} 

fl 

謝謝!

+0

在循環的第一次迭代的東西可讀,你的父母是0,因此是添加的兒童(添加歲後的孩子被添加到'fl')。這是故意的嗎? – kungfujam 2014-10-05 20:58:50

+0

@kungfujam在將它們添加到'fl'後,它看起來像所有的年齡都會立即增加。 – shadowtalker 2014-10-05 21:01:44

+0

是 - 有意。我希望他們在複製發生後(年齡結束)老化。 – jdfinch3 2014-10-05 21:06:07

回答

1

當您從列表中刪除元素,你是不是調整i4相應。試試這個:

###FIXED### 
    #KILL BASED ON AGE 
    i4 <- 0 
    while (i4 < length(fl)) { 
    i4 <- i4 + 1 
    if (fl[[i4]] > death) { 
     #ADD TO KILL LIST FOR DEBUGGING 
     kl <- c(kl, fl[[i4]]) 

     #REMOVE FROM fl 
     fl <- fl[-c(i4), drop=FALSE] 
     i4 <- i4 - 1 #    <------ added this line 
    } 
    } 

此外,你的代碼是相當非標準的(和一種難以閱讀)。這不是代碼審查,但我至少會建議使用for而不是while ......我認爲你的典型R用戶會更加適應這些。我不確定lapply其實是這裏的正確解決方案;它會失去一些循環的直接共鳴。但我會高度建議寫功能,而不是隻是一個循環的牆。然後,你可以這樣寫

life <- function(n_parents, n_children, death_age, n_generations) { 
    fl <- as.list(rep(0, n_parents)) 
    for (i in 1:n_generations) { 
    fl <- spawn_children(fl, n_children) 
    fl <- lapply(fl, `+`, 1) # increment ages by 1 
    fl <- kill_old_people(fl, death_age) 
    } 
    fl 
} 

life(
    n_parents = 10, 
    n_children = 5, 
    death_age = 3, 
    n_generations = 5 
) 
+0

我誠摯地感謝您的建議和批評。我在R中自學,我習慣於使用其他語言的循環,這只是我的解決方案。我真的需要更好地學習如何使用lapply,而不是while循環。同樣感謝你爲我的實際代碼提供了一個修復,並且對整個事情進行了(更多)更有說服力的重寫! – jdfinch3 2014-10-05 21:35:34

2

通常在使用R時,您可以避免循環。這很慢,有些功能可以用來避免它。我認爲你的原始代碼並不工作,因爲你在循環,你正在刪除一個元素,然後索引會改變,那麼在下一次迭代中,你最終會刪除錯誤的元素。我已經改變了你的代碼,看看你的想法:

#NUMBER OF PARENTS TO START WITH 
parents <- 10 
#NUMBER OF GENERATIONS TO RUN 
generations <- 5 
#NUMBER OF CHILDREN TO CREATE EACH GENERATION 
children <- 5 
#AGE TO KILL 
death <- 3 

pl <- list() 
cl <- list() 
fl <- list() 
kl <- list() 

#CREATE PARENTS 
# for (i2 in 1:parents) { 
#  pl[[i2]] <- 0 
# } 
fl <- pl <- as.list(rep(0, parents)) 

# fl <- pl 


#START GEN LOOP 

i3 <- 0 
while (i3 < generations) { 
    i3 <- i3 + 1 


    #CREATE CHILDREN 
#  for (i5 in 1:children) { 
#   cl[[i5]] <- 0 
#  } 

    cl <- as.list(rep(0, children)) 

    #ADD CHILDREN TO FINAL LIST 
    fl <- c(fl, cl) 

    #ADD 1 TO AGE 
#  for (i6 in 1:length(fl)) { 
#   fl[[i6]] <- fl[[i6]] + 1 
#  } 
    fl <- lapply(fl, function(x) x+1) 

    ###PROBLEM### 
    #KILL BASED ON AGE 
#  i4 <- 0 
#  while (i4 < length(fl)) { 
#   i4 <- i4 + 1 
#   if (fl[[i4]] > death) { 
#    
#    #ADD TO KILL LIST FOR DEBUGGING 
#    kl <- c(kl, fl[[i4]]) 
#    
#    #REMOVE FROM fl 
#    fl <- fl[-c(i4), drop=FALSE] 
#   } 
#  } 
    fl <- fl[fl <= death]  

    #CLOSE GEN LOOP 
} 

fl 

lapply是你的朋友

+0

謝謝 - 您的解決方案可行,代碼更簡單。爲了讓我明白未來,你能否解釋「fl < - fl [fl <= death]」是如何工作的?我不熟悉這種方法。 R中的 – jdfinch3 2014-10-05 21:41:53

+2

@ jdfinch3,可以使用邏輯向量來子集。考慮'一個< - 98:100'。然後'a [1]'返回與'a [c(TRUE,FALSE,FALSE)]'相同的東西。最重要的是,'<='是矢量化的,所以'5:7 <= 5'將返回'c(TRUE,FALSE,FALSE)',所以原則上可以使用'a [5:7 <= 1] '得到與'a [1]'相同的結果。這實際上是一個很常見的竅門,它可以爲你節省寫作的麻煩,比如'a [which(5:7 <= 5)]',在這種情況下,哪個(5:7 <= 5)返回'1'。 – shadowtalker 2014-10-05 23:24:29

+1

沒問題@ jdfinch3和謝謝@ssdecontrol步進。輸入'?'邏輯'到您的R控制檯獲取更多信息。 – kungfujam 2014-10-06 00:30:22