# Which programming pattern is best for checking which partition a number lies in?

I have an interval partitioned into “MECE” subintervals, and I want to check which subinterval a number lies in.

(MECE stands for “mutually exclusive & collectively exhaustive”, meaning the partitions do not overlap and they leave no gaps in between.)

First I simply used `if .. else if`:

``````;    if (0/6 <= h && h < 1/6) { rgb = [c, x, 0] }
else if (1/6 <= h && h < 2/6) { rgb = [x, c, 0] }
else if (2/6 <= h && h < 3/6) { rgb = [0, c, x] }
else if (3/6 <= h && h < 4/6) { rgb = [0, x, c] }
else if (4/6 <= h && h < 5/6) { rgb = [x, 0, c] }
else if (5/6 <= h && h < 6/6) { rgb = [c, 0, x] }
``````

Then I tried using the ternary operator:

``````rgb =
(0/6 <= h && h < 1/6) ? [c, x, 0] :
(1/6 <= h && h < 2/6) ? [x, c, 0] :
(2/6 <= h && h < 3/6) ? [0, c, x] :
(3/6 <= h && h < 4/6) ? [0, x, c] :
(4/6 <= h && h < 5/6) ? [x, 0, c] :
(5/6 <= h && h < 6/6) ? [c, 0, x] : [c, x, 0]
``````

I also read about how object lookups are a more performant alternative to switch statements. Since I’m not checking the exact value of `h`, I had to improvise:

``````rgb = ({
[`\${(0/6 <= h && h < 1/6)}`]: [c, x, 0],
[`\${(1/6 <= h && h < 2/6)}`]: [x, c, 0],
[`\${(2/6 <= h && h < 3/6)}`]: [0, c, x],
[`\${(3/6 <= h && h < 4/6)}`]: [0, x, c],
[`\${(4/6 <= h && h < 5/6)}`]: [x, 0, c],
[`\${(5/6 <= h && h < 6/6)}`]: [c, 0, x],
})['true']
``````

The problem with object lookup is that there will be five keys of `'false'`, which is not good practice. So I wanted to use a similar lookup, but using ES6 native `Map` class:

``````new Map([
[[0/6, 1/6], [c, x, 0]],
[[1/6, 2/6], [x, c, 0]],
[[2/6, 3/6], [0, c, x]],
[[3/6, 4/6], [0, x, c]],
[[4/6, 5/6], [x, 0, c]],
[[5/6, 6/6], [c, 0, x]],
]).forEach((value, key) => {
if (key[0] <= h && h < key[1]) rgb = value
})
``````

Which is the most readable, maintainable, fastest-running way to achieve this? Are there any other options?

• There's very little difference between these three. The performance differences are almost certainly inconsequential. Did you try measuring them to see which one performs the best? As a purely subjective opinion, I prefer the middle one. – Robert Harvey Mar 15 '19 at 19:27
• I would actually use `Math.floor(h*6)` as an index into some array, instead of these lengthy interval comparisons. – Doc Brown Mar 15 '19 at 21:38

Beauty (readability) lies in the eye of the beholder.

Speed depends upon algorithmic complexity, and efficient implementation. Different languages have different underlying support.

• cascaded if-else - 'multiple alternative selection structure', readable by the vast majority of developers, and works
• cascaded ternary (if-else) - same as first solution, less readable to some, but brief so better for others
• object lookups - less readable than a lookup table
• map lookup - readable, but not as intuitive to some developers, but readable

Now, some alternatives,

• partition hash-index function - as Doc Brown says, compose a function that calculates the partition, use the result as an index into a lookup table (array or hash/map). not very readable, and you need to compose the function. Not maintainable, as you need new function for every range change
• partition array & scan - iteratively scan array of partition boundaries to lookup value, easy to read and maintain, half as many comparisons
• decision tree - cascaded if-else by splitting ranges
• decision tree array - decision tree in data and traversal function

I'm not going to bother to present exact javascript syntax (this is SWE not SO), but this will give you alternatives.

partition hash-index function, essentially, compute k = h * 6 and lookup k in map

``````k = hash_function(h);
//hash_function(h) = ({ p=Math.floor(h*6)+1; p=(p<0 || p>6) ? 0 : p; })
partition_hash =
{ 0: [c, x, 0],
1: [c, x, 0],
2: [x, c, 0],
3: [0, c, x],
4: [0, x, c],
5: [x, 0, c],
6: [c, 0, x]
};
rgb = partition_hash[index];
``````

partition array & scan, iterate over array looking for boundary 'cuts', assumes continuous range (no gaps, the CE in MECE)

``````boundary_lookup =
[ [0,   [c, x, 0]],
[1/6, [c, x, 0]],
[2/6, [x, c, 0]],
[3/6, [0, c, x]],
[4/6, [0, x, c]],
[5/6, [x, 0, c]],
[6/6, [c, 0, x]]
];
rgb = boundary_lookup[index][0]
for( index=0; index<7; ++index ) {
if( h < boundary_lookup[index][0] ) rgb = boundary_lookup[index][1];
}
``````

decision tree, less readable, but cuts O(n)+1 tests into O(log2(n))+1

``````if( h < 0 || h > 1 ) {
rgb = [c, x, 0];
}
if( h < 3/6 ) {
if( h < 2/6 ) {
if( h < 1/6 ) { rgb = [x, c, 0] } // [1/6
else { rgb = [0, c, x] } // 2/6
}
else { rgb = [0, c, x] } //3/6
}
else {
if( h < 5/6 ) {// inrange [2/6 .. 3/6]
if( h < 4/6 ) { rgb = [x, 0, c] } // 4/6
else { rgb = [x, 0, c] } // 5/6
}
else { rgb = [0, c, x] } // 6/6
}
``````

decision tree array, uses an array to express decision tree boundary points, easy to read the values, but hard to write the traversal (left as an exercise), but fast, and not as ugly as the decision tree code, and once the traversal is written, can be reused

``````[ [3/6, [ [1/6, [c, x, 0]],
[2/6, [x, c, 0]],
[3/6, [0, c, x]]
]
],
[6/6, [ [4/6, [0, x, c]],
[5/6, [x, 0, c]],
[6/6, [c, 0, x]] ]
]
]
]
``````