Where is the bug in this serialize() function
I wrote a function deserialize() in Swift to construct a binary tree from an array of optional Integer. I tested this function by comparing the output with the output of a tree constructed using manual method with same array. They look the same, which is good !
However, when I run another function isSameTree(), that is used to compare 2 trees (I am sure this function is working correctly), on deserialize()'s output and manual method's output, I have different results !
I assume deserialize() is not correct, but I could not find the bug!
// helper code
public class BinaryNode {
public var value: Int
public var left: BinaryNode?
public var right: BinaryNode?
public init(_ value: Int) {
self.value = value
self.left = nil
self.right = nil
}
}
extension BinaryNode {
public var description: String {
return diagram(for: self)
}
private func diagram(for node: BinaryNode?,
_ top: String = "",
_ root: String = "",
_ bottom: String = "") -> String {
guard let node = node else {
return root + "nil\n"
}
if node.left == nil && node.right == nil {
return root + "\(node.value)\n"
}
return diagram(for: node.right,
top + " ", top + "┌──", top + "│ ")
+ root + "\(node.value)\n"
+ diagram(for: node.left,
bottom + "│ ", bottom + "└──", bottom + " ")
}
}
public func deserialize(_ array: inout [Int?]) -> BinaryNode? {
guard !array.isEmpty, let value = array.removeFirst() else {
return nil
}
let node = BinaryNode(value)
node.left = deserialize(&array)
node.right = deserialize(&array)
return node
}
func isSameTree(_ p: BinaryNode?, _ q: BinaryNode?) -> Bool {
guard let p = p else {
return q == nil
}
guard let q = q else {
return p == nil
}
if p.value != q.value {
return false
}
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right)
}
// Using deserialize to construct trees
var a1: [Int?] = [1,nil,2,3]
var a2: [Int?] = [1,nil,2,nil,3]
if let tree = deserialize(&a1) {
print(tree.description)
}
if let tree = deserialize(&a2) {
print(tree.description)
}
// Using manual to construct trees
let a3: BinaryNode = {
let one = BinaryNode(1)
let two = BinaryNode(2)
let three = BinaryNode(3)
one.right = two
two.left = three
return one
}()
print(a3.description)
let a4: BinaryNode = {
let one = BinaryNode(1)
let two = BinaryNode(2)
let three = BinaryNode(3)
one.right = two
two.right = three
return one
}()
print(a4.description)
// The print statements above show similar trees are constructed
// However, below results are not same
isSameTree(deserialize(&a1), deserialize(&a2)) // true <- this is wrong
isSameTree(a3, a4) // false <--- this is correct
Seems you have forgotten that your deserialize(_:) is destructive for its parameter... Please remember why you need &.
//Re-load a1 & a2...
a1 = [1,nil,2,3]
a2 = [1,nil,2,nil,3]
print(isSameTree(deserialize(&a1), deserialize(&a2))) //-> false
print(isSameTree(a3, a4)) //-> false
Related
I have a Node class defined as follows. value: T is a String
class Node<T> {
var value: T
weak var parent: Node?
var children = [Node<T>]()
init(_ value: T) {
self.value = value
}
func add(_ node: Node<T>) {
children.append(node)
node.parent = self
}
}
I'd like to build a function to return a String of the current Node's value and all Parent values. Ideally, the function would be defined in the class. For example,
currentnode.listAllValues()
would return -> "/parent2value/parent1value/currentnodevalue"
So far the following function works with a simple print(), and I've also considered using an inout parameter.
func listAllValues(node: Node<String>) {
print(node.value)
if node.parent?.value != nil {
listAllValues(node: node.parent!)
}
}
You can achieve this with an instance method which calls itself on the parent node first, if there is one:
func listAllValues() -> String {
if let p = parent {
return "\(p.listAllValues())/\(value)"
} else {
return "/\(value)"
}
}
Or as an obfuscated one-liner:
func listAllValues() -> String {
return "\(parent?.listAllValues() ?? "")/\(value)"
}
Example:
let p2 = Node("parent2value")
let p1 = Node("parent1value") ; p2.add(p1)
let n = Node("currentNodeValue") ; p1.add(n)
print(n.listAllValues())
// --> /parent2value/parent1value/currentNodeValue
Here you go:
func desc(_ s:String? = nil) -> String {
var me = String(describing:self.value)
if let prev = s {
me += "/" + prev
}
return self.parent?.desc(me) ?? me
}
Example:
let n = Node("hey")
n.add(Node("ho"))
n.children.first?.add(Node("nonny nonny no"))
let start = n.children.first!.children.first!
print(start.desc())
Implementing a Tree data structure using swift:
class Node {
var value: String
var children: [Node] = []
weak var parent: Node?
init(_ value: String) {
self.value = value
}
func add(_ child: Node){
children.append(child)
child.parent = self
}
func printTree() {
var text = self.value
if !self.children.isEmpty {
text += "\n " + self.children.map{$0.printTree()}.joined(separator: ", ")
}
print(text)
}
}
My goal is to see something like this:
A1
B2
C3
G6
K0
H7
L8
L9
I know there should be some smart way to insert indents, but I also struggle with 'map'. Compiler gives me "ambiguous reference to member 'map'".
If you want to make it pretty, you could do this:
extension Node
{
func treeLines(_ nodeIndent:String="", _ childIndent:String="") -> [String]
{
return [ nodeIndent + value ]
+ children.enumerated().map{ ($0 < children.count-1, $1) }
.flatMap{ $0 ? $1.treeLines("┣╸","┃ ") : $1.treeLines("┗╸"," ") }
.map{ childIndent + $0 }
}
func printTree()
{ print(treeLines().joined(separator:"\n")) }
}
a1.printTree()
// A1
// ┣╸B2
// ┣╸C3
// ┃ ┗╸G6
// ┗╸K0
// ┣╸H7
// ┃ ┗╸L8
// ┗╸L9
You could also generalize it into a print function for any tree structure that will let you choose what to print for each node:
func printTree<T>(_ node:T, _ nodeInfo:#escaping (T)->(String,[T]) )
{
func lines(_ aNode:T, _ nodeIndent:String="", _ childIndent:String="") -> [String]
{
let (label,children) = nodeInfo(aNode)
return [ nodeIndent + label]
+ children.enumerated().map{ ($0 < children.count-1, $1) }
.flatMap{ $0 ? lines($1,"┣╸","┃ ") :lines($1,"┗╸"," ") }
.map{ childIndent + $0 }
}
print( lines(node).joined(separator:"\n") )
}
// print a root node providing a capture to obtain the node's label
// and its array of children
printTree(a1){ ($0.value,$0.children) }
// works for any tree structure. for example, views :
printTree(view){( "\(type(of:$0)) \($0.frame)", $0.subviews )}
I think vacawama's answer is quite smart, but if you want to practice recursive call including maps, you can write something like this:
class Node {
//...
func treeLines() -> [String] {
return [self.value] + self.children.flatMap{$0.treeLines()}.map{" "+$0}
}
func printTree() {
let text = treeLines().joined(separator: "\n")
print(text)
}
}
To test:
let a1 = Node("A1")
let b2 = Node("B2")
let c3 = Node("C3")
let g6 = Node("G6")
let k0 = Node("K0")
let h7 = Node("H7")
let l8 = Node("L8")
let l9 = Node("L9")
a1.add(b2)
a1.add(c3)
a1.add(k0)
c3.add(g6)
k0.add(h7)
k0.add(l9)
h7.add(l8)
a1.printTree()
Output:
A1
B2
C3
G6
K0
H7
L8
L9
Some points:
Your printTree() is a void function, so using it in map produces an Array of empty tuples, which cannot be joined.
(In Swift, void functions can be considered as returning empty tuple. And Swift generates ambiguous reference to member when an appropriate overload cannot be found.)
You may need an intermediate function the result of which can represent a partial tree structure.
Indentation needs to be added to each line, so the intermediate result should easily be separated into lines.
Something like this should work:
func printTree(_ indent: String = "") {
print(indent + self.value)
for child in children {
child.printTree(indent + " ")
}
}
ruby has the function string.squeeze, but I can't seem to find a swift equivalent.
For example I want to turn bookkeeper -> bokepr
Is my only option to create a set of the characters and then pull the characters from the set back to a string?
Is there a better way to do this?
Edit/update: Swift 4.2 or later
You can use a set to filter your duplicated characters:
let str = "bookkeeper"
var set = Set<Character>()
let squeezed = str.filter{ set.insert($0).inserted }
print(squeezed) // "bokepr"
Or as an extension on RangeReplaceableCollection which will also extend String and Substrings as well:
extension RangeReplaceableCollection where Element: Hashable {
var squeezed: Self {
var set = Set<Element>()
return filter{ set.insert($0).inserted }
}
}
let str = "bookkeeper"
print(str.squeezed) // "bokepr"
print(str[...].squeezed) // "bokepr"
I would use this piece of code from another answer of mine, which removes all duplicates of a sequence (keeping only the first occurrence of each), while maintaining order.
extension Sequence where Iterator.Element: Hashable {
func unique() -> [Iterator.Element] {
var alreadyAdded = Set<Iterator.Element>()
return self.filter { alreadyAdded.insert($0).inserted }
}
}
I would then wrap it with some logic which turns a String into a sequence (by getting its characters), unqiue's it, and then restores that result back into a string:
extension String {
func uniqueCharacters() -> String {
return String(self.characters.unique())
}
}
print("bookkeeper".uniqueCharacters()) // => "bokepr"
Here is a solution I found online, however I don't think it is optimal.
func removeDuplicateLetters(_ s: String) -> String {
if s.characters.count == 0 {
return ""
}
let aNum = Int("a".unicodeScalars.filter{$0.isASCII}.map{$0.value}.first!)
let characters = Array(s.lowercased().characters)
var counts = [Int](repeatElement(0, count: 26))
var visited = [Bool](repeatElement(false, count: 26))
var stack = [Character]()
var i = 0
for character in characters {
if let num = asciiValueOfCharacter(character) {
counts[num - aNum] += 1
}
}
for character in characters {
if let num = asciiValueOfCharacter(character) {
i = num - aNum
counts[i] -= 1
if visited[i] {
continue
}
while !stack.isEmpty, let peekNum = asciiValueOfCharacter(stack.last!), num < peekNum && counts[peekNum - aNum] != 0 {
visited[peekNum - aNum] = false
stack.removeLast()
}
stack.append(character)
visited[i] = true
}
}
return String(stack)
}
func asciiValueOfCharacter(_ character: Character) -> Int? {
let value = String(character).unicodeScalars.filter{$0.isASCII}.first?.value ?? 0
return Int(value)
}
Here is one way to do this using reduce(),
let newChar = str.characters.reduce("") { partial, char in
guard let _ = partial.range(of: String(char)) else {
return partial.appending(String(char))
}
return partial
}
As suggested by Leo, here is a bit shorter version of the same approach,
let newChar = str.characters.reduce("") { $0.range(of: String($1)) == nil ? $0.appending(String($1)) : $0 }
Just Another solution
let str = "Bookeeper"
let newChar = str.reduce("" , {
if $0.contains($1) {
return "\($0)"
} else {
return "\($0)\($1)"
}
})
print(str.replacingOccurrences(of: " ", with: ""))
Use filter and contains to remove duplicate values
let str = "bookkeeper"
let result = str.filter{!result.contains($0)}
print(result) //bokepr
So I've built a swift playground that uses Dijkstra's algorithm to find the shortest route. However, I can't seem to manipulate my txt file so that my function will work in every case. It only works for a select few pathways. Whenever I map out a pathway I believe should work, it responds with: Execution was interrupted, reason: EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP, subcode=0x0).
How can I manipulate my txt file or my function/file manipulation to take my txt file input? (Where error occurred is marked -- near the bottom)
Usually the error occurs when trying to build a route backwards.
Ex: a1 to a3 works
Ex: a3 to a1 does not work
Code:
import Foundation
// Extensions
extension Array {
func each<U>(closure:(Element)->U?)->U? {
for i in self {
let returnVal = closure(i)
if (returnVal != nil) { return returnVal }
}
return nil
}
}
extension Int {
func times(closure:(Int)->Void) {
for i in 0..<self { closure(i) }
}
}
// Structs
struct Edge {
var wt: Double
var desV: Room
}
struct Graph { var vertices:[Room] }
// Room Class
class Room: Hashable {
var name: String?
var neighbors: [Edge] = []
var hashValue: Int {
get { return name!.hashValue }
}
init(){}
convenience init(name:String) {
self.init()
self.name = name
}
func distanceToRoom(targetRoom:Room) -> Edge? {
return self.neighbors.each({ (edge:Edge) -> Edge? in
if (edge.desV == targetRoom) {
return edge
}
return nil
})
}
}
// Functions
func == (lhs:Room, rhs:Room) -> Bool { return lhs.hashValue == rhs.hashValue }
func say( a:String ) { print( a, terminator:"") }
func dijkstra(graph:Graph, target:Room) -> [Room:Room] {
var queue = graph.vertices
var distances:[Room:Double] = [:]
var previousPaths:[Room:Room] = [:]
let currentRoom:Room = queue[0]
queue.each {(element:Room) -> Void? in
distances[element] = Double.infinity
previousPaths[element] = nil
return nil
}
distances[currentRoom] = 0
while (queue.count > 0) {
var closestNode:Room? = nil
let wt:Double = Double.infinity
queue.each({ (Room:Room) -> Void? in
if (closestNode == nil || wt < distances[Room]!) {
closestNode = Room
}
return nil
})
if (closestNode! == target) {
return previousPaths
}
let nodeIndex:Int? = queue.indexOf(closestNode!)
queue.removeAtIndex(nodeIndex!)
if (closestNode?.neighbors != nil && closestNode?.neighbors.count > 0) {
closestNode?.neighbors.each({(neighbor:Edge) -> Void? in
let wt = distances[closestNode!]! + closestNode!.distanceToRoom(neighbor.desV)!.wt
if wt < distances[neighbor.desV] {
distances[neighbor.desV] = wt
previousPaths[neighbor.desV] = closestNode!
}
return nil
})
}
}
return previousPaths
}
// File Management
//let url = NSURL(string:"file:///Users/caleb/Documents/Xcode/CRHS/CRHS/dtb.txt")!
let url = NSURL(string: "file:///Users/caleb/Desktop/rooms.txt")!
let data = NSData(contentsOfURL: url)
let sdata = String(data: data!, encoding: NSUTF8StringEncoding)
let dataArray = sdata!.characters.split{$0 == "\n"}.map(String.init)
var rooms = [String:Room]()
print("data:\n-------")
for i in 0 ..< dataArray.count {
let conn = dataArray[i].characters.split{$0 == "\t"}.map(String.init)
var room1: Room
if ( rooms[conn[0]] == nil ) {
room1 = Room(name: conn[0])
} else {
room1 = rooms[conn[0]]!
}
let room2 = Room(name: conn[2])
let edwt = (conn[1] as NSString).doubleValue
var edge = Edge(wt: edwt, desV: room2)
if room1.neighbors.count == 0 {
room1.neighbors = [ edge ]
} else {
var found: Bool = false
for e in room1.neighbors {
if ( e.desV.name == edge.desV.name ) {
found = true
}
}
if ( found == false ) {
room1.neighbors.append(edge)
}
}
rooms[conn[0]] = room1
}
for (nam,room) in rooms {
print(nam)
print("----")
for n in room.neighbors {
if let un = n.desV.name {
print( un, terminator: " weight: ")
}
print( n.wt )
}
print("\n")
}
var namessofrooms = rooms.map { $0.0 }
var roomsofrooms = rooms.map { $0.1 }
print("Rooms:")
print(rooms)
print("-------\n")
// Calculating
var source = rooms["a1"]!
var target = rooms["a4"]!
roomsofrooms.append(source)
var reversedRooms: Array = roomsofrooms.reverse()
reversedRooms.append(target)
var graph = Graph(vertices: reversedRooms)
var paths = dijkstra(graph, target: target)
var pathVertices:[Room] = [target]
var child = target
while (child != source) {
print(child.name)
print(":::::")
child = paths[child]! //Error occurs here
print(child.name)
pathVertices.append(child)
}
var pathString:[String] = pathVertices.reverse().map { (Room:Room) -> String in
return Room.name!
}
print("solution:\n-------")
print(pathString)
Below is the file I input:
a1 1 a2
a2 1 a3
a3 1 a4
If I input the following file the code above will not work:
a1 1 a2
a2 1 a3
a3 1 a4
a4 1 a5
(Update: File Map Clarification)
First column is the first room, second is the weight between the rooms, third is the room connected to the first.
I ran the same code in Xcode 7beta/rc Playground project and got an error:
Execution was interrupted, reason: EXC_BAD_ACCESS(code=EXC_I386_GPFLT)
in
let n: Int = Int(Process.arguments[1])!
How do I solve in Playground project since other solutions don't seem to be related?
Binary tree: http://benchmarksgame.alioth.debian.org/u64q/program.php?test=binarytrees&lang=swift&id=1
class TreeNode {
var left, right : TreeNode?
var item : Int
init(_ left: TreeNode?, _ right: TreeNode?, _ item: Int) {
self.left = left
self.right = right
self.item = item
}
func check() -> Int {
guard let left = left, let right = right else {
return item
}
return item + left.check() - right.check()
}
}
func bottomUpTree(item: Int, _ depth: Int) -> TreeNode {
if depth > 0 {
return
TreeNode(
bottomUpTree(2*item-1, depth-1),
bottomUpTree(2*item, depth-1),
item
)
}
else {
return
TreeNode(nil,nil,item)
}
}
let n: Int = Int(Process.arguments[1])!
let minDepth = 4
let maxDepth = n
let stretchDepth = n + 1
let check = bottomUpTree(0,stretchDepth).check()
print("stretch tree of depth \(stretchDepth)\t check: \(check)")
let longLivedTree = bottomUpTree(0,maxDepth)
var depth = minDepth
while depth <= maxDepth {
let iterations = 1 << (maxDepth - depth + minDepth)
var check = 0
for i in 0..<iterations {
check += bottomUpTree(i,depth).check()
check += bottomUpTree(-i,depth).check()
}
print("\(iterations*2)\t trees of depth \(depth)\t check: \(check)")
depth += 2
}
print("long lived tree of depth \(maxDepth)\t check: \(longLivedTree.check())")
Process.arguments holds the value that is passed as arguments for a command-line application.
But you're using it in a Playground: there's no access to command line input from a Playground (they are Sandboxed), so Process.arguments is nil and your app crashes when you're doing Process.arguments[1].
The solution is to use this in an actual application, not in a Playground.
You can use a custom "readLine()" function and a global input variable, each element in the input array is presenting a line:
import Foundation
var currentLine = 0
let input = ["5", "5 6 3"]
func readLine() -> String? {
if currentLine < input.endIndex {
let line = input[currentLine]
currentLine += 1
return line
} else {
return nil
}
}
let firstLine = readLine() // 5
let secondLine = readLine() // 5 6 3
let thirdLine = readLine() // nil