Создание объекта узла из аргументов var-args - PullRequest
0 голосов
/ 25 мая 2020

У меня есть следующий класс узла

class Node<T> {
    var data: T
    var next: Node<T>?

    init(_ items: Any...) {
       // self.data = items[0] as! T
    }
}

, и моя цель - инициализировать узел с помощью конструктора, указанного выше:

var sampleNode = Node<Any>(Node<Int>(2, 15), 4, Node<Any>(5, Node<Int>(7, 9)))

Как можно Я добиваюсь этого с помощью varargs?

1 Ответ

0 голосов
/ 25 мая 2020

Ключевая проблема здесь - «как мне объединить элементы в items в большой список?». Мы можем упростить задачу до меньшего: «Как мне объединить 2 Any s, которые могут быть T или Node<T>, в один список, представленный Node<T>?». (Это то, что делает combine2Anys ниже). Вы можете легко увидеть, что существует 4 случая этой проблемы:

  • первый элемент - Node<T>, второй элемент - T,
  • оба элемента Node<T>
  • первый раз T, второй элемент Node<T>
  • оба элемента T

Вам просто нужно обрабатывать каждый случай по очереди. Затем используйте этот метод с первыми двумя элементами из items, затем с результатом этого и третьего элемента, затем с результатом этого и четвертого элемента и т. Д.

class Node<T> {
    var data: T
    var next: Node<T>?

    init(_ items: Any...) {
        func combine2Anys(_ x: Any, _ y: Any) -> Node<T> {
            switch (x, y) {
            case (let node as Node<T>, let t as T):
                node.end.next = Node(data: t, next: nil)
                return node
            case (let node1 as Node<T>, let node2 as Node<T>):
                node1.end.next = node2
                return node1
            case (let t as T, let node as Node<T>):
                return Node(data: t, next: node)
            case (let t1 as T, let t2 as T):
                return Node(data: t1, next: Node(data: t2, next: nil))
            default:
                // something other than Node<T> and T are in the passed in array
                fatalError()
            }
        }

        if items.count == 0 {
            fatalError() // it's undefined what we should do when items is empty
        } else if items.count == 1 {
            data = items.first as! T
            next = nil
        } else {
            var combined = combine2Anys(items[0], items[1])
            for i in 2..<items.count {
                combined = combine2Anys(combined, items[i])
            }
            data = combined.data
            next = combined.next
        }
    }

    // find the last node of the list
    var end: Node<T> {
        var node = self
        while node.next != nil {
            node = node.next!
        }
        return node
    }

    init(data: T, next: Node<T>?) {
        self.data = data
        self.next = next
    }
}

Использование:

let list = Node<Int>(1, Node<Int>(2, 15), 4, Node<Int>(5, Node<Int>(7, 9)))

Обратите внимание, что вы должны постоянно использовать один и тот же общий c тип.

Но на самом деле это действительно некрасиво, в основном из-за слепков и прочего. Вы теряете всю безопасность типов во время компиляции. Я предполагаю, что это одно из тех «странных требований домашней работы». Если бы я сделал это в реальном мире, я бы изменил использование на:

let list = Node(Node(1), Node(Node(2), Node(15)), Node(4), Node(Node(5), Node(Node(7), Node(9))))

И вместо этого у меня были бы эти два инициализации:

init(_ items: Node<T>...) {
    if items.count == 1 {
        data = items.first as! T
        next = nil
    } else {
        items[0].end.next = items[1]
        for i in 2..<items.count {
            items[i - 1].end.next = items[i]
        }
        data = items[0].data
        next = items[0].next
    }
}

init(_ item: T, next: Node<T>? = nil) {
    self.data = item
    self.next = next
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...