使用 R 中的 for 和 if 语句在fluidRow() 中进行迭代

Posted

技术标签:

【中文标题】使用 R 中的 for 和 if 语句在fluidRow() 中进行迭代【英文标题】:Iteration inside fluidRow() with for and if statement in R 【发布时间】:2020-11-24 04:08:52 【问题描述】:

我正在尝试在 bs4TabItem 中使用fluidRow,它最多有 3 个 bs4UserCard 项目。 FluidRows 应该在 for 循环中动态构建,并且最大。 3 bs4UserCard 也应该在 for 循环中动态构建。下面是代码的sn-p。我已经根据其他建议尝试了 UI 和服务器部分中的代码,但它仍然不起作用。

# Get number of rows from dataset
records = nrow(candidatesDF)

# Each row will have max. 3 items
numRows = ceiling(nrow(candidatesDF) / 3)
numRows = c(1:numRows)

count = 0
offset = 3

candidates =  bs4TabItem(tabName = "candidates",
  for (row in numRows) 
    fluidRow(
      if (records < offset) 
        offset = records
      
      for (column in 1:offset) 
        count = count + 1

        # Convert the names to a more legible format
        name = explode(candidatesDF[count, "Candidate"], sep = ", ")
        name = paste0(name[2], ' ', name[1])
        name = capitalizeStrings(name, all.words = TRUE, lower.back = TRUE)

        # Convert the names to the img name format
        imgName = explode(name, sep = " ")
        imgName = tolower(implode(imgName, "_"))
        imgUrl = paste0("img/", imgName, ".png")

        # Create a user card on each iteration.
        bs4UserCard(
          title = name,
          subtitle = candidatesDF[count, "Party"],
          type = NULL,
          width = 4,
          src = imgUrl,
          status = "danger",
          closable = TRUE,
          elevation = 4,
          imageElevation = 4,
          fluidRow(
            column(
              width = 4,
              descriptionBlock(header = "District",
               text = capitalizeStrings(candidatesDF[count, "District"],
                      all.words = TRUE, lower.back = TRUE ))
            ),
            column(
              width = 4,
              descriptionBlock(header = "Votes",
               text = candidatesDF[count, "Votes"])
            ),
            column(
              width = 4,
              descriptionBlock(header = "Result",
               text = candidatesDF[count, "Result"], right_border = FALSE)
            )
          )
        )

        records = records - 1
      
    ) 
   
)

使用 if 语句我得到这个错误

Possible missing comma at:
87:  for (row in fluidRows) 
              ^

如果我仅出于测试目的删除 if 语句,我会收到此错误

Warning: Error in explode: Assertion on 'x' failed: May not be NA.

我不确定explode 中的x 如何是NA,因为我在数据集中没有任何NA 值。当我逐行运行代码测试explode函数时,返回了预期的结果,所以我不明白为什么NA​​。

尽管如此,我的目标是创建 x 数量的 fluidRows,每行最多包含 3 个项目,这些项目的信息是从数据集中动态生成的。 ################################################## ###################### 我已更新代码以反映使用 lapply() 的建议。

# Get number of rows from dataset
records = nrow(candidatesDF)

# Each row will have max. 3 items
numRows = ceiling(nrow(candidatesDF) / 3)
numRows = c(1:numRows)

count = 0
offset = 3

checkOffset = function(records, offset) 
  if (records < offset) 
    offset = records
  
  
  return(offset) 



candidates =  bs4TabItem(tabName = "candidates",
 lapply(numRows, function(r) 
   fluidRow(
     lapply(1:checkOffset(records, offset), function(c) 
       count = count + 1
       print(count)
       # Convert the names to a more legible format
       name = explode(candidatesDF[count, "Candidate"], sep = ", ")
       name = paste0(name[2], ' ', name[1])
       name = capitalizeStrings(name, all.words = TRUE, lower.back = TRUE)

       # Convert the names to the img name format
       imgName = explode(name, sep = " ")
       imgName = tolower(implode(imgName, "_"))
       imgUrl = paste0("img/", imgName, ".png")
       
       records = records - 1
       
       # Create a user card on each iteration.
       bs4UserCard(
         title = name,
         subtitle = candidatesDF[count, "Party"],
         type = NULL,
         width = 4,
         src = imgUrl,
         status = "primary",
         closable = TRUE,
         elevation = 4,
         imageElevation = 4,
         fluidRow(
           column(
             width = 4,
             descriptionBlock(header = "District",
              text = capitalizeStrings(candidatesDF[count, "District"],
                     all.words = TRUE, lower.back = TRUE ))
           ),
           column(
             width = 4,
             descriptionBlock(header = "Votes",
              text = candidatesDF[count, "Votes"])
           ),
           column(
             width = 4,
             descriptionBlock(header = "Result",
              text = candidatesDF[count, "Result"], right_border = FALSE)
           )
         )
       )
     )
   )
 )

虽然这对接近预期结果有很大帮助,但每个网格中的每张卡片都是相同的。那是因为count变量不递增,record变量也不递增。

提前致谢。

【问题讨论】:

你想让这个响应吗?或者只是试图在服务器启动时硬编码元素的数量? for R 中的循环不返回值。你应该做的是建立一个list() 的对象,你想插入到 UI 中,然后将该列表传递给fluidRow()。如果您提供最小的reproducible example,则更容易提供帮助。删除任何对问题不重要的代码。 请尝试lapply 而不是for 循环。正如 MrFlick 指出的那样,MRE 将有助于识别任何其他问题。 @MrFlick 我希望循环使用代表数据集中每一行的索引生成所需的值。我认为我在问题中放置的代码足以重现,所以我不确定要添加什么,并且链接不太清楚,因为有很多可能性。 @YBS 我已经删除了 for 循环并用 lapply 替换它们。这达到了一定程度。它能够生成预期的行数和列数,但不会在每次迭代中增加计数变量。因此它将显示相同的用户卡。 @Ravi,如果没有完全可重现的代码,很难调试。我会考虑的两个项目是:(1)不需要定义numRows = c(1:numRows),而是你应该定义lapply(1:numRows, …,(2)对于第二个lapply,请尝试lapply(1:(checkOffset(records, offset)),... 【参考方案1】:

根据@YBS 的建议将 for 循环切换到 lapply 后,我的主要问题变成了弄清楚为什么 count 和 record 变量在第一次 lapply 迭代后不会保持它们的值。

答案是使用 can lapply not modify variables in a higher scope找到解释。

【讨论】:

以上是关于使用 R 中的 for 和 if 语句在fluidRow() 中进行迭代的主要内容,如果未能解决你的问题,请参考以下文章

如何在 R 中保存循环(使用 if 语句)的结果?

如何用lambda表达式改写LinQ语句?

break是终止本次循环还是结束循环

TYPO3 Fluid complex if 条件

根据条件替换R数据帧中的值[重复]

R语言中的if else语句