问题描述
我正在尝试了解如何使用矢量构建对象.我认为这很简单,但是当我在对象上使用 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>.
然后我尝试对自身创建强制转换,除非由于某种原因未定义默认方法:
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() 和子集方法以隐藏此实现细节.
使用上面链接中的示例作为模板,我们可以实现您的案例:
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"
请注意,我们不需要创建强制转换方法,在这种情况下,记录的默认强制转换方法就足够了.
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 包构建对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!