首页 > 解决方案 > 如何使用可以与 c() 结合的 R vctrs 包构建对象

问题描述

我试图了解如何使用向量构建对象。我认为这很简单,但是当我在对象上使用 c() 时遇到了麻烦。

我们的对象有两个属性,x 和描述符,在这种情况下都是字符串(我的对象将具有不同类型的属性)。我们已经构建了一个构造函数 new_toy_vector。我还没有在这个例子中建立一个便利函数。

new_toy_vector <- function(
  x = character(),
  descriptor = character()) {

  vctrs::vec_assert(x,character())
  vctrs::vec_assert(descriptor, character())

  vctrs::new_vctr(x,
                  descriptor = descriptor,
                  class = "toy_vector")
}



format.toy_vector <- function(x, ...) {
  paste0(vctrs::vec_data(x)," is ", attr(x, "descriptor"))
}

obj_print_data.toy_vector <- function(x) {
  cat(format(x), sep = "\n")
}

c(new_toy_vector("Hello", "Foo"), new_toy_vector("World", "Bar"))
#> Error: No common type for `..1` <toy_vector> and `..2` <toy_vector>.

reprex 包(v0.3.0)于 2020-04-26 创建

然后我尝试用自己创建一个强制,除非由于某种原因没有定义默认方法:

> vec_ptype2.toy_vector.toy_vector <- function(x, y, ...) new_toy_vector()
> c(new_toy_vector("Hello", "Foo"), new_toy_vector("World", "Bar"))
Error: Can't convert <toy_vector> to <toy_vector>.

有什么我想念或误解的想法吗?为什么我不能合并示例中的两个对象?

标签: rtidyversevctrs

解决方案


通常,当对象被子集时,属性不会被子集,这不是规则,“名称”属性是一个突出的例子,它不遵循这种做法。要创建行为类似于“名称”的属性,您必须跳过障碍,而{vctrs}旨在为您简化此类任务。

我们使用{vctrs}的方式是使用记录,我们不需要属性:

记录样式对象使用等长向量列表来表示对象的各个组件。最好的例子是 POSIXlt,它的底层是一个包含 11 个字段的列表,例如年、月和日。记录风格的类覆盖 length() 和子集方法来隐藏这个实现细节。

使用上面链接中的示例作为模板,我们可以实现您的案例:

new_toy_vector <- function(
  value = character(),
  descriptor = character()) {
  vctrs::vec_assert(value,character())
  vctrs::vec_assert(descriptor, character())
  vctrs::new_rcrd(list(value = value, descriptor = descriptor), class = "toy_vector")
}


format.toy_vector <- function(x, ...) {
  value <- vctrs::field(x, "value")
  descriptor <- vctrs::field(x, "descriptor")
  paste0('"', value," is ", descriptor, '"')
}

v1 <- new_toy_vector(
  c("Hello", "World"), 
  c("Foo", "Bar"))

v2 <- c(
  new_toy_vector("Hello", "Foo"), 
  new_toy_vector("World", "Bar"))

v1
#> <toy_vector[2]>
#> [1] "Hello is Foo" "World is Bar"

identical(v1, v2)
#> [1] TRUE

v2[2]
#> <toy_vector[1]>
#> [1] "World is Bar"

reprex 包(v0.3.0)于 2021-01-23 创建

请注意,我们不需要创建强制方法,在这种情况下,记录的默认强制方法就足够了。


推荐阅读