如何使用R中其他列的值格式化字符串

tv6aics1  于 12个月前  发布在  其他
关注(0)|答案(3)|浏览(111)

我需要做一些字符串格式化使用值从其他列由逗号分隔.让我们假设我有一个 Dataframe 这样:

words <- c('%s + %s equal %s', '%s + %s equal %s')
arguments <- c('1,1,2', '2,2,4')
df <- data.frame(words, arguments)
df
             words    arguments
1 %s + %s equal %s        1,1,2
2 %s + %s equal %s        2,2,4

字符串
我需要一个这样的结果:

words    arguments         combined
1 %s + %s equal %s        1,1,2    1 + 1 equal 2
2 %s + %s equal %s        2,2,4    2 + 2 equal 4


你知道我该怎么做吗?

x6h2sr28

x6h2sr281#

words列非常适合sprintf。请尝试以下操作:

df$combined <- apply(df, 1, function(x) do.call(sprintf, 
                       c(as.list(strsplit(x[2], ',')[[1]]), fmt = x[[1]])))
df

#             words arguments      combined
#1 %s + %s equal %s     1,1,2 1 + 1 equal 2
#2 %s + %s equal %s     2,2,4 2 + 2 equal 4

字符串
我们将arguments的值拆分到","上,使用do.call将它们作为sprintf的单独参数传递,并创建combined字符串。apply中的x[2]引用arguments列,而x[1]用于words列。

gxwragnw

gxwragnw2#

非常类似于Ronak的解决方案,但为了简洁起见使用了一些data.tablepurrr

library(purrr)
library(data.table)

df$combind <- map_chr(
  seq_len(nrow(df)), 
  ~do.call(sprintf, c(fmt = df$words[.], tstrsplit(df$arguments[.], ",")))
)

#              words arguments       combind
# 1 %s + %s equal %s     1,1,2 1 + 1 equal 2
# 2 %s + %s equal %s     2,2,4 2 + 2 equal 4

字符串

6ju8rftf

6ju8rftf3#

正如@Spacedman正确指出的那样,以前的解决方案不再起作用了。这也是正确的,应该尽可能避免eval-parse解决方案。谢谢@dash2:你说得很好。
因此,这里遵循一个新的tidyverse和R-基地的解决方案。

使用tidyverse

具体为:dplyrpurrrstringr

library(tidyverse)

df |> 
  mutate(
    # split arguments by comma
    arguments = str_split(arguments, ","),

    # loop over words and arguments and call sprintf via do.call
    combind = map2_chr(words, arguments, 
                       \(...) do.call("sprintf", as.list(c(...)))))

#>              words arguments       combind
#> 1 %s + %s equal %s   1, 1, 2 1 + 1 equal 2
#> 2 %s + %s equal %s   2, 2, 4 2 + 2 equal 4

字符串
注意,do.call的第二个参数必须是被调用函数的参数列表(在本例中为sprintf)。这就是为什么words的每一项都要与arguments的每一项合并(c),然后强制合并为一个列表(as.list)。

使用Base R

df$combind <- mapply(\(...) do.call("sprintf", as.list(c(...))), 
                     df$words, strsplit(df$arguments, ","))

df

#>              words arguments       combind
#> 1 %s + %s equal %s   1, 1, 2 1 + 1 equal 2
#> 2 %s + %s equal %s   2, 2, 4 2 + 2 equal 4


让我们一步一步来看看解决方案:

# loop simultaneously over the two columns of df via mapply
# (to see the solution step by step SIMPLIFY is set to FALSE)
mapply(c, df$words, strsplit(df$arguments, ","), SIMPLIFY = FALSE) |>
 
  # now set each vector to a list (to use do.call)
  lapply(as.list) |> 

  # call sprintf via do.call
  # (sapply is being used over lapply to force the simplicification of the list into a character vector)
  sapply(do.call, what = "sprintf")

#> %s + %s equal %s %s + %s equal %s 
#>  "1 + 1 equal 2"  "2 + 2 equal 4"

相关问题