I need to check if none of the values in two IntArray objects differ by more than 1.
This is the working code, which takes too long:
var pixelOutsideOfTolerance = false
val PIXEL_VALUE_TOLERANCE = 1
for (i in 0 until pixels1.lastIndex) {
if (pixels1[i] - pixels2[i] > PIXEL_VALUE_TOLERANCE && pixels1[i] - pixels2[i] < - PIXEL_VALUE_TOLERANCE) {
pixelOutsideOfTolerance = true
}
}
// Do something with pixelOutsideOfTolerance
What would be a more performant and eloquently way to do this?
>Solution :
Before fixing performance, you must ensure correctness:
- you have an off-by-one error because
lastIndexis the actual last index, not the size. Usefor (i in pixels1.indices)instead of explicit ranges to avoid this kind of mistakes - your condition can never be true, because you’re using
&&instead of||. Useabs(pixels1[i] - pixels2[i]) > PIXEL_VALUE_TOLERANCEinstead of the more complicated condition checking both positive and negative, it will be simpler to read and less likely to get wrong (you’ll needimport kotlin.math.abs)
Now you’re doing the whole loop even when you already know some pixel differences are outside the tolerance. Extract a function for this loop, and return early when the "outside tolerance" condition is met.
Applying the above, you should now have:
import kotlin.math.abs
private const val PIXEL_VALUE_TOLERANCE = 1
private fun areSimilar(pixels1: IntArray, pixels2: IntArray): Boolean {
for (i in pixels1.indices) {
if (abs(pixels1[i] - pixels2[i]) > PIXEL_VALUE_TOLERANCE) {
return false
}
}
return true
}
// then just use
val pixelsOutsideOfTolerance = !areSimilar(pixels1, pixels2)
If performance was not a requirement, you could also use a more functional approach here. For instance:
val pixelsOutsideOfTolerance = pixels1.indices.any {
abs(pixels1[it] - pixels2[it]) > PIXEL_VALUE_TOLERANCE
}
Or:
val pixelsOutsideOfTolerance = pixels1.asSequence().zip(pixels2.asSequence())
.any { abs(it.first - it.second) > PIXEL_VALUE_TOLERANCE }
But if it’s really a hot path that you are trying to speed up, that will be counter-productive because of boxing.