Как установить значение по умолчанию слота как NULL в R? - PullRequest
11 голосов
/ 19 сентября 2011

Я новичок в R.

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

setClass('Node', representation=(left='Node',right='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, тогда значением по умолчанию будет рекурсивный узел глубины 4, который, я думаю, является пустой тратой ресурсов.

Мое соображение не нужно или есть лучший способ сделать это?

Ответы [ 2 ]

9 голосов
/ 19 сентября 2011

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

7 голосов
/ 19 сентября 2011

Это исправленный ответ.

Объединения классов - это фанки - они эффективно вставляют класс в середину существующей иерархии, поэтому внезапно вещи, расширяющие 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 < t@elem) {
        l <- insert(x, t@left)
        r <- t@right
    } else {
        l <- t@left
        r <- insert(x, t@right)
    }
    Tree(t@elem, 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 < t@elem) member(x, t@left)
    else if (t@elem < x) member(x, t@right)
    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 и потому, что изменение дерева (например, добавление узла) копирует все узлы на пути к новому узлу. другой подход представляет дерево в виде matrix левой, правой и тройной значений. Реализация S4 все еще будет иметь низкую производительность, потому что обновления экземпляра будут создавать новые экземпляры, дублируя все. Таким образом, я бы оказался в ссылочном классе с полями 'value' (вектором того, что дерево должно содержать, и matrix левых и правых отношений.

...