My first question on StackOverflow :)
I started to learn Swift in XCode a few days ago and I'm having some trouble understanding the value type in Swift. Since I'm quite familiar with Java, I'm just going to explain my question in Java. Here's what I want to write in Swift.
class Node {
public int value;
public List<Integer> children;
public Node parent;
public Node() {
value = 0;
children = new ArrayList<Integer>();
}
public Node bestChild() {
Node result = new Node();
for (child : this.children) {
if (child.value > result.value)
result = child;
}
return result;
}
}
For the sake of this question, let's not talk about private, public, or generic here. Just keep it simple! Here's my try in Swift.
public class Node {
var value: Int
var children: NSSet
var parent: Node?
public init() {
self.value = 0
children = NSSet()
}
public func bestChild() -> Node {
var result = Node()
for child in children {
if (child.value > result.value) { //error
result = child //error
}
}
return result
}
}
Both the condition for the if statement and the line inside have errors. XCode suggested casting the variables but still it didn't solve the errors.
if ((child as AnyObject).value > result.value) {
result = child as! Node
}
Since Java is the only language I know, if someone could explain it in term of Java I would greatly appreciate it. If not, please keep it simple so I can wrap my head around it :)
Thanks in advance!
welcome to Stack Overflow and Swift programming!
Firstly, I suggest some changes to the Java code.
children
variable is type List<Integer>
, but I suspect you meant it to be List<Node>
.Node
just for comparison's sake. With this approach, if bestChild()
returns a Node
with a value of 0, it can't be known if that's because the children list was empty, of if there really was a Node
with value 0 that was the highest value. I would use the stream API, though you could manually implement such functionality.Here is the end result:
class Node {
public int value;
public List<Node> children = new ArrayList<>();
public Node parent; // Unused?
public Node bestChild() {
// Modern, easy approach:
return children
.stream()
.max((x, y) -> Integer.compare(x.value, y.value))
.get();
// Old, classic Java approach:
/*
int max = Integer.MIN_VALUE;
Node maxNode = null;
for (Node child : this.children) {
if (max < child.value) {
max = child.value;
maxNode = child;
}
}
return maxNode; */
}
}
Here's how I would write this in Swift. Feel free to ask follow up questions
class Node {
let value = 0
let children = [Node]()
weak var parent: Node? // Unused?
func bestChild() -> Node? {
return children.max(by: { $0.value < $1.value })
}
}
Here's the Swift implementation of the antiquated Java approach to the bestChild
method. This is just for comparison's sake. DON'T DO THIS!
func bestChild() -> Node? {
var max = Int.min
var maxNode: Node?
for child in children {
if max < child.value {
max = child.value
maxNode = child
}
}
return maxNode
}
NSSet
is to Swift
, as HashSet
(without the generic type parameter, not HashSet<T>
) is to Java. It's a datatype from the Foundation
library, that was invented for Objective-C. You shouldn't be using it in Swift in 99.999% of cases. NSSet
acts as a set of AnyObject
. In order to be able to call .value
on an object from the set, you need to first manually cast the object to Node
.
The solution to all that is to instead use Set<Int>
, which is Swift's native Set
data structure. Though this raises the question, why are you using a Set in the swift solution, but an array in the Java solution?