I need a function which finds the left and right neighbor-element within an integer-array, based upon a given index. If the given element is 0, then it shall return largest index as left neighbor. When the given index is the largest index, then it shall return 0 as right neighbor.
Here's the solution, I have created:
// ------- Actual function ----------------------
func findNeighborsWithin(array: [Int], viewingElement index: Int) -> [Int] {
var neighbors = [Int]()
if index > 0 {
neighbors.append(index - 1)
} else {
neighbors.append(array.count - 1)
}
if index < array.count - 1 {
neighbors.append(index + 1)
} else {
neighbors.append(0)
}
return neighbors
}
// ------------------------------------------------
// Testing/Example-usage
let array = [0, 1, 2, 4, 8, 16, 32, 64]
print("Index 0 -> \(findNeighborsWithin(array: array, viewingElement: 0))")
print("Index \(array.count - 1) -> \(findNeighborsWithin(array: array, viewingElement: array.count - 1))")
for i in 0..<5 {
let randInt = Int.random(in: 0..<array.count)
print("Index \(randInt) -> \(findNeighborsWithin(array: array, viewingElement: randInt))")
}
/*
Index 0 -> [7, 1]
Index 7 -> [6, 0]
Index 4 -> [3, 5]
Index 6 -> [5, 7]
Index 3 -> [2, 4]
Index 5 -> [4, 6]
Index 6 -> [5, 7]
*/
What's are your thoughts on my solution, including naming and formatting? Is there a better solution? How can it become improved? What would you have done differently and why?
1 Answer 1
Some notes:
The contents and the element type of the array is irrelevant to the outcome of the function, only the array count is needed. Therefore I would pass that count as an argument instead of an entire array.
The function always returns a pair of indices, therefore I would use a two-element (named) tuple as the return type instead of an array.
The function returns something even if the passed index it invalid for the given array. I suggest to test the parameters with a precondition.
The conditional operator
?:
can be used to compute the left and right indices instead ofif
statements.In the spirit of the Swift Naming Guidelines I would call the function something like
neighboringIndices(for:inArrayOfLength:)
Putting it together, I suggest the following implementation:
func neighboringIndices(for index: Int, inArrayOfLength count:Int) -> (left: Int, right: Int) {
precondition(index >= 0 && index < count, "Invalid index")
let leftNeighbor = index == 0 ? count - 1 : index - 1
let rightNeighbor = index == count - 1 ? 0 : index + 1
return (leftNeighbor, rightNeighbor)
}
Alternatively, with a "branchless" computation:
let leftNeighbor = (index - 1 + count) % count
let rightNeighbor = (index + 1) % count
Testing/example usage:
let array = [0, 1, 2, 4, 8, 16, 32, 64]
print(neighboringIndices(for: 0, inArrayOfLength: array.count)) // (7, 1)
print(neighboringIndices(for: 3, inArrayOfLength: array.count)) // (2, 4)
print(neighboringIndices(for: array.count - 1, inArrayOfLength: array.count)) // (6, 0)
// Access return value via named tuple accessors:
let neighbors = neighboringIndices(for: 5, inArrayOfLength: array.count)
print(neighbors.left) // 4
print(neighbors.right) // 6
// Invalid index:
print(neighboringIndices(for: 999, inArrayOfLength: array.count))
// Precondition failed: Invalid index
In addition I suggest to add unit tests.
-
\$\begingroup\$ The
% count
branchless solution is the shortest and most beautiful solution \$\endgroup\$muescha– muescha2025年08月03日 20:51:18 +00:00Commented Aug 3 at 20:51