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

问题描述 投票:0回答:3

我需要使用其他列中以逗号分隔的值进行一些字符串格式化。假设我有一个像这样的数据框:

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

知道我该怎么做吗?

r string dataframe string-formatting
3个回答
2
投票

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
字符串。
x[2]
中的
apply
指的是
arguments
列,而
x[1]
则代表
words
列。


1
投票

与 Ronak 的解决方案非常相似,但为了简洁使用了一些

data.table
purrr

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

-1
投票

正如@Spacedman 正确指出的那样,之前的解决方案不再有效。尽可能避免 eval-parse 解决方案也是正确的。谢谢@dash2:你说得很好。

所以这里有一个新的 tidyverse 和 R-base 解决方案。


tidyverse

具体:

dplyr
purrr
stringr

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
的每个项目都与
c
的每个项目组合 (
arguments
),然后强制放入列表 (
as.list
)。


带底座R

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

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

# 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"
© www.soinside.com 2019 - 2024. All rights reserved.