如何使用可以与 c() 结合的 R vctrs 包构建对象 [英] How do I build an object with the R vctrs package that can combine with c()

查看:13
本文介绍了如何使用可以与 c() 结合的 R vctrs 包构建对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to understand how to build objects with vectors. I thought this was straightforwards, but then had trouble when I used c() on my object.

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

Our object has two attributes, x and descriptor, both strings in this case (my object will have attributes with differing types). We've built a constructor, new_toy_vector. I haven't built a convenience function in this example yet.

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 年 4 月 26 日创建

Created on 2020-04-26 by the reprex package (v0.3.0)

然后我尝试对自身创建强制转换,除非由于某种原因未定义默认方法:

I then tried to create a coercion with itself unless the default method wasn't defined for some reason:

> 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>.

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

Any ideas what I'm missing or misunderstanding? Why can't I combine the two objects in the example?

推荐答案

一般来说,当对象被子集化时,属性不会被子集化,这不是规则,名称"也没有被子集化.属性是一个突出的例子,它不遵循这种做法.创建一个行为类似于名称"的属性您必须跳过障碍,{vctrs} 旨在为您简化此类任务.

Generally attributes are not subsetted when an object is subsetted, this is not a rule and the "names" attribute is a prominent example which doesn't follow this practice. To create an attribute that behaves like "names" you'd have to jump through hoops, and {vctrs} was designed to simplify this kind of tasks for you.

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

The way we do this with {vctrs} is by using records, and we won't need attributes :

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

Record-style objects use a list of equal-length vectors to represent individual components of the object. The best example of this is POSIXlt, which underneath the hood is a list of 11 fields like year, month, and day. Record-style classes override length() and subsetting methods to conceal this implementation detail.

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

Using the example in the link above as a template we can implement your case :

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 年 1 月 23 日创建

Created on 2021-01-23 by the reprex package (v0.3.0)

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

Note that we didn't need to create a coercion method, in this case the default coercion method for records is good enough.

这篇关于如何使用可以与 c() 结合的 R vctrs 包构建对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆