Method: Array#nearest_index
- Defined in:
- lib/openc3/core_ext/array.rb
#nearest_index(value, ordered_data = true) ⇒ Integer
Returns the array index nearest to the passed in value. This only makes sense for numerical arrays containing integers or floats. It has an optimized algorithm if the array is sorted but will fail if passed unsorted data with the sorted option.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/openc3/core_ext/array.rb', line 60 def nearest_index(value, ordered_data = true) raise "Cannot search on empty array" if self.empty? if ordered_data last_index = self.length - 1 first_value = self[0].to_f last_value = self[-1].to_f return 0 if first_value == last_value slope = last_index.to_f / (last_value - first_value) offset = -(slope * first_value) guess_index = ((slope * value.to_f) + offset).to_i # Return immediately for boundary conditions return 0 if guess_index < 0 return last_index if guess_index > last_index # Verify guess index previous_guess_index = nil previous_guess_value = nil # While in the valid range of indexes while guess_index >= 0 and guess_index <= last_index # Retrieve the value at our current guess index guess_value = self[guess_index] # We're done if we found the exact value return guess_index if guess_value == value if previous_guess_value # Determine if we did better or worse # Was previous guess better or worse? if (guess_value - value).abs <= (previous_guess_value - value).abs # Previous Guess Worse or the same if guess_value > value # Moving with decreasing indexes if previous_guess_value > value # Still moving in right direction previous_guess_index = guess_index guess_index -= 1 else # We passed the value return guess_index end else # guess_value < value and moving with increasing indexes if previous_guess_value < value # Still moving in right direction previous_guess_index = guess_index guess_index += 1 else # We passed the value return guess_index end end else # Previous Guess Better return previous_guess_index end else # Move to the next point previous_guess_index = guess_index if guess_value > value guess_index -= 1 else # guess_value < value guess_index += 1 end end previous_guess_value = guess_value end # Return our best guess return 0 if guess_index < 0 return last_index else # Brute force search # Calculate the initial delta min_delta = (self[0] - value).abs closest_index = 0 self.each_with_index do |self_value, index| # Calculate the delta between the current value and value we are # searching for delta = (value - self_value).abs # If the newly calculate delta is less than or equal to are previous # minimum delta then we proceed if delta <= min_delta # There is a special case if the delta is equal to the previously # calculated delta. We want to round up in this case so we check if # the value we are searching for is greater than the current value. # If so we skip this value since we don't want to round down. next if (delta == min_delta) and (value > self_value) min_delta = delta closest_index = index end end return closest_index end end |