如何在列表中减去序号

时间:2018-12-05 12:39:42

标签: r

我在数据框中有一些文本,如下所示

输入

rownumber  CStage
1           38-40cm
2           27-22
3           32cm and 40cm

我想在每个CStage中减去两个数字,输出为

所需的输出

rownumber  CStage
1           2
2           5
3           8

我用过stringr::str_extract_all(df$CStage,"\\d{2}")

这给了我一个列表,每个元素包含两个数字

[[1]]
[1] "38" "40"

[[2]]
[1] "27" "22"

[[3]]
[1] "32" "40"

然后我该如何减去两个数字(以获得正输出)

3 个答案:

答案 0 :(得分:3)

就像@Cath在评论中提到的那样,您可以使用sapply,将其转换为数字,并在它们之间采用diff的含义。

num_list <- stringr::str_extract_all(df$CStage,"\\d{2}")
abs(sapply(num_list, function(x) diff(as.numeric(x))))
#[1] 2 5 8

答案 1 :(得分:1)

您也可以sort,然后使用diff。

sapply(regmatches(df1$CStage, gregexpr("\\d+", df1$CStage)), function(x)diff(sort(as.numeric(x))))
#[1] 2 5 8

答案 2 :(得分:1)

1)绑可以使用gsubfn中的strapply紧凑地完成此操作。定义一个正则表达式,以便为CStage的每个元素提取捕获组中的两个数字,并将它们传递到公式符号中定义的匿名函数中,并返回差的绝对值。

library(gsubfn)

transform(DF, CStage = strapply(CStage, 
                                "(\\d+)\\D+(\\d+)", 
                                ~ abs(as.numeric(x) - as.numeric(y)),
                                simplify = TRUE))

给予:

  rownumber CStage
1         1      2
2         2      5
3         3      8

2)基本R 通过用CStage中的空格替换非数字,并使用read.table读取它们以创建数据框,可以获得基本R解决方案具有V1和V2列。减去这些列并取绝对值。

transform(DF, CStage = with(read.table(text = gsub("\\D", " ", CStage)), abs(V1-V2)))

给予:

  rownumber CStage
1         1      2
2         2      5
3         3      8

3)dplyr / tidyr 一种使用dplyr和tidyr的解决方案,其方法与(2)类似:

library(dplyr)
library(tidyr)

DF %>%
  separate(CStage, into = c("V1", "V2"), sep = "\\D+", 
    extra = "drop", convert = TRUE) %>%
  mutate(CStage = abs(V1 - V2)) %>%
  select(rownumber, CStage)

给予:

  rownumber CStage
1         1      2
2         2      5
3         3      8

注意

可重复输入的形式是:

Lines <- "
rownumber,CStage
1,38-40cm
2,27-22
3,32cm and 40cm"

DF <- read.csv(text = Lines, as.is = TRUE)