如何使用toString创建字符串?

时间:2019-06-20 07:20:52

标签: r data.table tostring

我有一个包含2列的数据表:类别和优先级。我使用for循环以以下方式对数据进行分类:

  • 我检查实际值的优先级是否小于 上一个。
  • 我将类别的值保存在“ new”列中。
  • 我将类别的先前值保存在列中的字符串中 “ rest”。
  • 如果实际值的优先级较高,则相反 操作。

我已经尝试使用功能pastepaste0toString,但是我无法达到预期的效果。

priority <- c(3,2,1,4,5,6,7)
category <- c("a","b","c","d","e","f","g")

data.dt <- data.table(priority,category)
data.dt$new <- NA
data.dt$rest <- NA
for (i in 2:nrow(data.dt)){
  if(data.dt$priority[i]<=data.dt$priority[i-1]){
    data.dt$new[[i]] <- data.dt$category[i]
    data.dt$rest[[i]] <- toString(data.dt$category[i-1])
    }
  else{
    data.dt$new[[i]] <- data.dt$category[i-1]
    data.dt$rest[[i]] <- toString(data.dt$category[i])
  }
  }

这是我的结果:

   priority category  new rest
1:        3        a <NA> <NA>
2:        2        b    b    a
3:        1        c    c    b
4:        4        d    c    d
5:        5        e    d    e
6:        6        f    e    f
7:        7        g    f    g

但是我想要以下一个:

   priority category  new rest
1:        3        a <NA> <NA>
2:        2        b    b    a
3:        1        c    c    a,b
4:        4        d    c    a,b,d
5:        5        e    d    a,b,d,e
6:        6        f    e    a,b,d,e,f
7:        7        g    f    a,b,d,e,f,g

1 个答案:

答案 0 :(得分:2)

您接近了,只需添加1:x序列(表示为#)而不是单个值即可。

data.dt$new <- NA
data.dt$rest <- NA

for (i in 2:nrow(data.dt)) {
  if(data.dt$priority[i] <= data.dt$priority[i-1]) {
    data.dt$new[[i]] <- data.dt$category[i]
    data.dt$rest[[i]] <- toString(data.dt$category[1:(i-1)])  #
  }
  else{
    data.dt$new[[i]] <- data.dt$category[i-1]
    data.dt$rest[[i]] <- toString(data.dt$category[1:i])  #
  }
}
#    priority category  new                rest
# 1:        3        a <NA>                <NA>
# 2:        2        b    b                   a
# 3:        1        c    c                a, b
# 4:        4        d    c          a, b, c, d
# 5:        5        e    d       a, b, c, d, e
# 6:        6        f    e    a, b, c, d, e, f
# 7:        7        g    f a, b, c, d, e, f, g

或者,您可以使用for,而无需进行diff循环。 (您无需事先创建NA。)

data.dt$new <- 
  with(data.dt, ifelse(c(NA, diff(priority)) < 0, category, c(NA, category)))

说明: diff计算每个值与先前值的差;如果ifelseif,我们将应用else(向量化的diff< 0)。

sl <- c(NA, Map(function(x) toString(data.dt$category[seq(x)]), seq(nrow(data.dt))))
data.dt$rest <- ifelse(c(NA, diff(data.dt$priority)) < 0, sl, sl[-1])

data.dt
#    priority category  new                rest
# 1:        3        a <NA>                  NA
# 2:        2        b    b                   a
# 3:        1        c    c                a, b
# 4:        4        d    c          a, b, c, d
# 5:        5        e    d       a, b, c, d, e
# 6:        6        f    e    a, b, c, d, e, f
# 7:        7        g    f a, b, c, d, e, f, g

更新

要摆脱rest列中出现的new列中的值,可以使用以下代码省略match es:

sc <- Map(function(x) c(data.dt$category[seq(x)]), seq(nrow(data.dt)))
data.dt$rest <- unlist(c(NA, Map(function(x, y) 
  toString(x[is.na(match(x, y))]), sc, data.dt$new)[-1]))

说明:对于rest列,我们希望seq的{​​{1}}带有我们用sc实现的实际行的长度。因为我们不希望这些值已经出现在Map列中,所以我们在应用new之前将match scdata.dt$new一起使用。 toString为我们提供了一个矢量,因为我们不需要一列类列表。

查看unlist会发现它已按?Map的顺序将FUN部分依次应用于以下两个对象 Map(FUN, x, y)。结果收集在列表中。对于第四个元素,如下所示:

# Map(FUN, x, y)
(x <- sc[[4]])
# [1] "a" "b" "c" "d"
(y <- data.dt$new[[4]])
# [1] "c"
toString(x[is.na(match(x, y))])  # FUN
# [1] "a, b, d"

结果

data.dt
#   priority category  new             rest
# 1        3        a <NA>             <NA>
# 2        2        b    b                a
# 3        1        c    c             a, b
# 4        4        d    c          a, b, d
# 5        5        e    d       a, b, c, e
# 6        6        f    e    a, b, c, d, f
# 7        7        g    f a, b, c, d, e, g

数据

data.dt <- structure(list(priority = c(3, 2, 1, 4, 5, 6, 7), category = c("a", 
"b", "c", "d", "e", "f", "g")), row.names = c(NA, -7L), class = c("data.table", 
"data.frame"))