【问题标题】:How to convert playtime to seconds in R如何在R中将播放时间转换为秒
【发布时间】:2021-09-07 20:11:25
【问题描述】:

我有一个向量如下:

playtimes <- c("1H18M20S", "1H27M5S", "18M27S", "56M38S", "21S")

我想在秒内将这些转换为播放时间。例如,生成的向量会是这样的:

playtimeInSeconds <- c(4700, 5225, 1107, 3398, 21)

我无法根据 H、M 和 S 正确分离字符串。我写了以下内容,适用于 1 小时以下的播放时间

minutes <- gsub("M.*", "", playtime)
seconds <- gsub(".*M", "", playtime) %>%
    gsub("S", "", .)

totalPlaytime <- as.numeric(minutes)*60 + as.numeric(seconds)

但我不确定如何处理某些字符串的 H 部分。

【问题讨论】:

标签: r


【解决方案1】:

您可以strsplit 并将列表元素reversely 的length 调整为3,这允许您使用sapply 来获得一个矩阵,您可以在其中应用矩阵乘积%*%

m <- sapply(strsplit(p, 'H|M|S'), \(x) as.double(rev(`length<-`(rev(x), 3))))
res <- as.vector(t(replace(m, is.na(m), 0)) %*% rbind(3600, 60, 1))
res
# [1] 4700 5225 1107 3398   21

【讨论】:

    【解决方案2】:

    有趣的问题。这是一个可能更有效但可以完成工作的解决方案

    # function from https://www.statworx.com/de/blog/strsplit-but-keeping-the-delimiter/
    strsplit <- function(x,
                         split,
                         type = "remove",
                         perl = FALSE,
                         ...) {
      if (type == "remove") {
        # use base::strsplit
        out <- base::strsplit(x = x, split = split, perl = perl, ...)
      } else if (type == "before") {
        # split before the delimiter and keep it
        out <- base::strsplit(x = x,
                              split = paste0("(?<=.)(?=", split, ")"),
                              perl = TRUE,
                              ...)
      } else if (type == "after") {
        # split after the delimiter and keep it
        out <- base::strsplit(x = x,
                              split = paste0("(?<=", split, ")"),
                              perl = TRUE,
                              ...)
      } else {
        # wrong type input
        stop("type must be remove, after or before!")
      }
      return(out)
    }
    
    
    # convert to seconds
    to_seconds <- c(H = 60 * 60,
                    M = 60,
                    S = 1)
    
    get_seconds <- function(value, unit) {
      value * to_seconds[unit]
    }
    
    
    # example vector
    playtimes <- c("1H18M20S", "1H27M5S", "18M27S", "56M38S", "21S")
    
    # extract time parts
    times <- strsplit(playtimes, 
                      split = "[A-Z]",
                      type = "after")
    times
    #> [[1]]
    #> [1] "1H"  "18M" "20S"
    #> 
    #> [[2]]
    #> [1] "1H"  "27M" "5S" 
    #> 
    #> [[3]]
    #> [1] "18M" "27S"
    #> 
    #> [[4]]
    #> [1] "56M" "38S"
    #> 
    #> [[5]]
    #> [1] "21S"
    
    # calculate each time in seconds
    sapply(times,
           function(t) {
             # split numeric and unit part
             t_split <- strsplit(x = t,
                                 split = "[A-Z]",
                                 type = "before")
             
             # calculate seconds for each unit part
             times_in_seconds <- get_seconds(value = as.numeric(sapply(t_split, `[`, 1)),
                                             unit = sapply(t_split, `[`, 2))
             
             # sum of all parts
             sum(times_in_seconds)
           })
    #> [1] 4700 5225 1107 3398   21
    

    【讨论】:

      【解决方案3】:

      我按照第三个答案here中给出的示例进行了以下操作

      playtime <- sapply(playtime, function(x){paste(paste(rep(0, 3 - str_count(x, '[0-9]+')), collapse = ' '), x)})
      totalPlaytime <- time_length(hms(playtime))
      

      短小精悍,并检查播放时间少于 1 小时或少于 1 分钟的潜在错误。

      【讨论】:

        猜你喜欢
        • 2023-04-07
        • 2016-06-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-05
        • 1970-01-01
        • 1970-01-01
        • 2011-08-28
        相关资源
        最近更新 更多