【问题标题】:Make for loop change after 4 iterations--ie run for loop in sets of four, with separate function in between在 4 次迭代后进行 for 循环更改——即以四个为一组运行 for 循环,中间有单独的函数
【发布时间】:2022-01-11 22:21:41
【问题描述】:

我不知道描述这个的正确方式,所以请多多包涵。基本上,我在 R 中有一个函数,它可以读取数据框并按特定顺序粘贴内容——它用于为 LaTeX 编写 tex 文件,因此我可以非常快速地制作数百个标签。

我附上了一个只有 for 循环的简化版本。我希望做的是让代码循环遍历四行数据,为第五行做一些不同的事情,然后返回接下来的四行数据。在下面的示例中,它将为大多数行粘贴一个短语,而在第五行它将粘贴其他内容——每个都基于数据框。

对于我的实际代码,我想水平翻转标签以尽可能多地使用纸张。见附图。,但实际上这一切都归结为我认为的 for 循环。

data <- data.frame(title = c("big Cactus", "little cactus", "bad cactus", "skinny cactus", 
                             "round cactus", "spiny cactus", "twisty cactus", "bizarre cactus"),
                   name = c("Franklin", "Stephanie", "Megan", "Mark", 
                            "Patricia", "KD", "Claude", "Audrey"),
                   needs = c("nothing", "some love", "too much", "some water", 
                             "some sunlight", "new soil", "transplanted", "a friend"))

for (this.label in 1:dim(data)[1]) {
#main function I want for every label
  line <- paste0(data$name[this.label], " the ", data$title[this.label], " needs ", data$needs[this.label])
  print(line)
  }

example of alternate function for every fourth row of the data frame:
line <- paste0(data$name[this.label], " is feeling left out!")

【问题讨论】:

  • 在您的for 循环中,只需使用模运算符%% 测试您的索引this.label,如下所示:if(this.label %% 5 == 0){execute alternate function} else {execute main function}。假设您从1 开始计数,那么此测试将每五个循环评估为TRUE(对于this.label ∈ {51015,...}),因此执行备用“功能”(代码)。
  • @Dion 虽然*apply() 系列会构成更好的做法,但我不确定它是否允许访问迭代索引,那么是否有办法区分每五行?
  • @Dion 无需深入研究源代码,您在if 语句中测试的索引变量的名称是什么?
  • @Dion 哦,对不起。我以为你的意思是在data.frame 本身上使用*apply()。在这种情况下,我认为*apply() 函数的这种用法只会使事情复杂化。
  • @Greg 好像是you are right。不知道,谢谢!

标签: r for-loop


【解决方案1】:

这是一个基本 R 中的解决方案,只需对现有代码进行最少的修改。

解决方案

在您的 for 循环中,只需使用模运算符 %% 测试您的索引 this.label,如下所示:

for (this.label in seq_len(nrow(data))) {
  if (this.label %% 5 == 0) {
    # example of alternate function for every fourth row of the data frame:
    line <- paste0(data$name[this.label], " is feeling left out!")
  } else {
    # main function I want for every label
    line <- paste0(data$name[this.label], " the ", data$title[this.label], " needs ", data$needs[this.label])
  }
  
  print(line)
}

这个测试

this.label %% 5 == 0

每五个循环将评估为TRUE(对于this.label ∈ {51015,...}),因此执行备用“函数”(技术上是“表达式”) ;而其他四个循环将简单地执行“主函数”(表达式)。

结果

根据您的示例代码以及示例中的data

data <- data.frame(
  title = c("big Cactus", "little cactus", "bad cactus", "skinny cactus", "round cactus", "spiny cactus", "twisty cactus", "bizarre cactus"),
  name = c("Franklin", "Stephanie", "Megan", "Mark", "Patricia", "KD", "Claude", "Audrey"),
  needs = c("nothing", "some love", "too much", "some water", "some sunlight", "new soil", "transplanted", "a friend")
)

此解决方案应产生所需的输出:

[1] "Franklin the big Cactus needs nothing"
[1] "Stephanie the little cactus needs some love"
[1] "Megan the bad cactus needs too much"
[1] "Mark the skinny cactus needs some water"
[1] "Patricia is feeling left out!"
[1] "KD the spiny cactus needs new soil"
[1] "Claude the twisty cactus needs transplanted"
[1] "Audrey the bizarre cactus needs a friend"

注意

我已将笨重的 1:dim(data)[1] 替换为 seq_len(nrow(data)),这是用于迭代表行的 proper way。在表为空(0 行)的情况下,这可以防止任何针对不存在行的 1:0(即c(1, 0))循环。

【讨论】:

  • 好吧,太棒了!这看起来很棒!我会试一试!还要感谢关于笨重部分的更新——自学会导致很多笨拙的事情。
  • @Tyler “自学会导致很多笨拙的事情。”不用担心!我们都是来学习的。 :)
  • 所以这工作非常顺利!虽然我需要重新设计 LaTeX 格式来处理这些变化——但它现在每 11 行实现一个备用函数!谢谢!!
【解决方案2】:
make_label_A <- function(this.label) {
  line <- paste0(data$name[this.label], " the ", data$title[this.label], " needs ", data$needs[this.label])
  print(line)
}

make_label_B <- function(this.label) {
  line <- paste0(data$name[this.label], " is feeling left out!")
  print(line)
}

for (i in seq(1,dim(data)[1], 5)) {
  sapply(1:4, \(x) make_label_A(i+x))
  make_label_B(i+4)
}

希望这与您使用的 LaTeX 引擎非常一致。有时打印语句需要更小心地在循环内显示。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-20
    • 2012-05-20
    • 1970-01-01
    • 2019-05-12
    相关资源
    最近更新 更多