0

I have an array of SCNNode that are sorted by their y positions(Float):

nodesSortedByY = scene.rootNode.childNodes.sorted { $0.position.y > $1.position.y }

What I would like to do is get a new array from nodesSortedByY where the y values are within a certain range in a similar way to how subscript works but by passing actual values not indexes.

For example:

let nodesSortedByY = [5.0, 4.0, 4.0, 3.0, 2.0, 2.0, 1.0]
let subRange = nodesSortedByY(4.0...2.0)
print(subRange) // [4.0, 4.0, 3.0, 2.0, 2.0]

I tried using indexes originally combined with this binary search but it doesnt work if the values dont exist within the array:

let yPositions = nodesSortedByY.map({ $0.position.y })
let firstIndex = yPositions.binarySearch(forFirstIndexOf: firstValue) ?? 0
let lastIndex = yPositions.binarySearch(forLastIndexOf: lastValue) ?? 0
nodesSortedByY[lastIndex...firstIndex]
Wazza
  • 1,725
  • 2
  • 17
  • 49
  • Are you looking for `filter()`? `let filtered = nodesSortedByY.filter({ (2.0...4.0).contains($0) })` – Larme Oct 22 '20 at 14:26
  • Not quite, it would have to be filtered by a range of the nodes y positions somehow? – Wazza Oct 22 '20 at 14:30
  • DIdn't you want to get all the values of "y" if they are between 2.0 and 4.0? That's what's doing the filter. Else, keeping your last idea: `let lowerBound = nodesSortedByY.firstIndex(where: { $0 <= 4.0 }) let upperBound = nodesSortedByY.lastIndex(where: { $0 >= 2.0 }) let sub = nodesSortedByY[lowerBound!...upperBound!]` – Larme Oct 22 '20 at 14:33
  • i want an array of SCNNode still but sorting it by `y` and getting the the new range array by the nodes y values – Wazza Oct 22 '20 at 14:36
  • I guess so, but the author used `map`, and simplified his example to `[Double]`, but my solutions should work. – Larme Oct 22 '20 at 14:37
  • A hack would be to modify the first suggestion somewhat to filter in the sorted order, `nodesSortedByY.filter { (-4.0 ... -2.0).contains(-$0)}` – Joakim Danielson Oct 22 '20 at 14:43

1 Answers1

1

What you want is to filter().

let sub = nodesSortedByY.filter { (2.0...4.0).contains($0.position.y) }

We keep only the elements in nodesSortedByY where its y position is inside the range [2.0; 4.0].

Since you sorted your array (descending order), you can applied that logic too (modification of your attempt)

let lowerBound = nodesSortedByY.firstIndex(where: { $0 <= 4.0 }) ?? nodesSortedByY.startIndex
let upperBound = nodesSortedByY.lastIndex(where: { $0 >= 2.0 }) ?? nodesSortedByY.endIndex
let sub = nodesSortedByY[lowerBound...upperBound]
Larme
  • 24,190
  • 6
  • 51
  • 81