Как установить значение по умолчанию для слота как NULL в R?

Я новичок в R.

Я пытаюсь определить класс, похожий на дерево node, то есть он имеет левый node и правый node, который должен быть того же класса, что и родительский node. Поэтому я определяю класс следующим образом:

setClass('Node', representation=(left='Node',right='Node', ...))

Я хочу установить значение по умолчанию node равным NULL, установив прототип, но R говорит следующее:

  invalid class "Node" object: invalid object for slot "left" in class "bicluster": got class "NULL", should be or extend class "Node"

Но если я не укажу значение по умолчанию равным NULL, то значением по умолчанию будет рекурсивный node глубины 4, который, по моему мнению, является пустой тратой ресурсов.

Является ли мое соображение ненужным или есть лучший способ сделать это?

Ответ 1

Это пересмотренный ответ.

Разновидности классов фанки - они эффективно вставляют класс в середину существующей иерархии, так что теперь вещи, расширяющие list, теперь расширяются listOrNULL.

Вместо этого я бы создал небольшую иерархию классов, которая представляет собой "Дерево", которое может быть "Пусто" или "Внутреннее". Класс "Внутренний" будет иметь слот для хранения данных (типа "ЛЮБОЙ" ) плюс левые и правые ссылки, которые будут элементами "Дерево".

setClass("Tree")

setClass("Empty", contains="Tree")

setClass("Internal", contains="Tree",
         representation=representation(elem="ANY", left="Tree", right="Tree"),
         prototype=prototype(left=new("Empty"), right=new("Empty")))

Я напишу конструктор для моего дерева с методами для создания пустого дерева и дерева из элемента плюс левого и правого потомков.

setGeneric("Tree", function(elem, left, right) standardGeneric("Tree"),
           signature="elem")

setMethod(Tree, "missing", function(elem, left, right) new("Empty"))

setMethod(Tree, "ANY", function(elem, left, right) {
    new("Internal", elem=elem, left=left, right=right)
})

Основная операция - вставить элемент x в дерево t

setGeneric("insert", function(x, t) standardGeneric("insert"))

setMethod(insert, c("ANY", "Empty"), function(x, t) {
    Tree(x, Tree(), Tree())
})

setMethod(insert, c("ANY", "Internal"), function(x, t) {
    if (x < [email protected]) {
        l <- insert(x, [email protected])
        r <- [email protected]
    } else {
        l <- [email protected]
        r <- insert(x, [email protected])
    }
    Tree([email protected], l, r)
})

Другая операция - проверить членство

setGeneric("member", function(x, t) standardGeneric("member"))

setMethod(member, c("ANY", "Empty"), function(x, t) FALSE)

setMethod(member, c("ANY", "Internal"), function(x, t) {
    if (x < [email protected]) member(x, [email protected])
    else if ([email protected] < x) member(x, [email protected])
    else TRUE
})

Интересным, функциональным свойством этой реализации является постоянство

> t <- Tree()
> t1 <- insert(10, t)
> t2 <- insert(5, t1)
> t3 <- insert(7, t2)
> t4 <- insert(15, t3)
> which(sapply(1:20, member, t4))
[1]  5  7 10 15
> which(sapply(1:20, member, t2))
[1]  5 10

Это не будет эффективным, когда будет много обновлений из-за неэффективности создания класса S4, и поскольку изменение дерева (например, добавление node) копирует все узлы в пути к новому node. A другой подход представляет дерево как matrix слева, справа, значение трижды. Реализация S4 по-прежнему будет иметь низкую производительность, поскольку обновления экземпляра создадут новые экземпляры, дублируя все. Таким образом, я попал бы в ссылочный класс с полях "значение" (вектор любого дерева, который должен удерживать, и matrix левого и правого отношений.

Ответ 2

В одно время вам нужно было использовать setClassUnion("listOrNULL",members=c("list", "NULL")), чтобы получить NULL в слот, который был определен как список. Я думаю, что теперь это доступный класс. Не удается проверить, пока ваша установка неполна, но определение суперкласса "NodeOrNull" может привести вас к вашему первоначальному барьеру.