R - 根据年龄杀死

时间:2014-10-05 20:27:34

标签: r list loops

我正在尝试设置一些感觉应该很简单的东西,但我无法找到解决方案。我写了一个我的代码的精简版本,试图在整个过程中解释它。

基本上,我想每一代创建一组“孩子”。然后,将每年的年龄加1,并在年龄> 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

谢谢!

2 个答案:

答案 0 :(得分: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是你的朋友

答案 1 :(得分: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
)