views:

386

answers:

6

I've got the following scenario:

There are three ("pseudo" randomly chosen) int or float values which represent indices of an array. Now I'd like to compare the appropriate values from that array. After having compared them I'd like to know the middle value of the three and use this specific element for some further array operations.

The question is, what is the fastest way of finding the middle of the three within Java? My idea was this kind of pattern - as there are three numbers there are 6 possible permutations. Obviously, there is some ugly overhead and the flow of control isn't really that clearly laid out...

if (array[randomIndexA] >= array[randomIndexB] &&
    array[randomIndexB] >= array[randomIndexC])

It would be really nice, if someone could help me out with a better and faster way of doing this. Even a plain logical form with clauses would be a nice thing...
Have a nice weekend anyway :D

+4  A: 

Here's how you can express this using only conditionals:

int a, b, c = ...
int middle = (a <= b) 
    ? ((b <= c) ? b : ((a < c) ? c : a)) 
    : ((a <= c) ? a : ((b < c) ? c : b));

EDITS:

  1. Errors in above found by @Pagas have been fixed.
  2. @Pagas also pointed out that you cannot do this with fewer than 5 conditionals if you only use conditional, but you can reduce this using temporary variables or value swapping.
  3. I would add that it is hard to predict whether a pure conditional or assignment solution would be faster. It is likely to depend on how good the JIT is, but I think the conditional version would be easier for the optimizer to analyse.
Stephen C
hey... your first answer was completely different using min and max. Why change it? I thought it was a good approach
Toad
@reinier ... it wasn't my answer.
Stephen C
stephen: euh? was it a removed answer from someone else? ah oh well... maybe it didn't work and they removed it or something
Toad
You do not need to do so many comparison - expand this to if-else statemetns and you can see you have a layer too much of "?"'s.
Thorbjørn Ravn Andersen
5 comparisons where 2 suffice? way to go.
rsp
@reinier: it was 'Stephan202' who deleted his answer.
Jonathan Leffler
Should be:(a <= b) ? ((b <= c) ? b : ((a < c) ? c : a)) : ((a <= c) ? a : ((b < c) ? c : b))
Paggas
You cannot avoid having at least 5 conditionals, unless you do things like value swapping or recursion. This is because the corresponding decision tree has 6 leaves, which means 5 internal nodes, thus 5 decision points in the whole code, though only two or three of them will be active at a time, those in the path to the answer leaf. But maybe the size of the code, or at least the number of conditionals, can be reduced by using swapping or other techniques!
Paggas
A: 

Using idxA to idxC in ary,

int ab = ary[idxA] < ary[idxB] ? idxA : idxB;
int bc = ary[idxB] < ary[idxC] ? idxB : idxC;
int ac = ary[idxA] < ary[idxC] ? idxA : idxC;

int idxMid = ab == bc ? ac : ab == ac ? bc : ab;

indexMiddle points to the middle value.

Explanation: from the 3 minima 2 are the overall minimum and the other value must be the middle. Because we check equality we can compare the indices in the last line instead of having to compare the array values.

rsp
This gives the *minimum* value, rather than the *middle* one.
Tim
Lol, did you try it? first line sets indexAB to the maximum of A and B, second line sets indexMiddle to the minimum of that maximum and C, giving you the middle value.I guess you missed the "index_B_ : index_A_" part of the first line?
rsp
Except that if C is the smallest value, this will produce C rather than the middle value.
jk
Sorry, no, I didn't try it, and you're right, I misread it. My apologies. However, the point is that you can't do it in just two comparisons, as illustrated by jk above.
Tim
Oops, you are correct. I replaced it with a solution I beleive is correct now :-)
rsp
A: 

or a one liner for finding the index in the array containing the middle value:

 int middleIndex = (a[0]<a[1]) ? ((a[0]<a[2) ? a[2] : a[0]) : ((a[1]<a[2) ? a[2] : a[1]);
Toad
Firstly, this gives a value, rather than an index. Secondly, for `a[0] < a[1] < a[2]` it gives `a[2]` as the answer, which is incorrect.
Tim
Snippets like this are a good reason for unit testing :)
Thorbjørn Ravn Andersen
+5  A: 

If you are looking for the most efficient solution, I would imagine that it is something like this:

if (array[randomIndexA] > array[randomIndexB]) {
  if (array[randomIndexB] > array[randomIndexC]) {
    return "b is the middle value";
  } else if (array[randomIndexA] > array[randomIndexC]) {
    return "c is the middle value";
  } else {
    return "a is the middle value";
  }
} else {
  if (array[randomIndexA] > array[randomIndexC]) {
    return "a is the middle value";
  } else if (array[randomIndexB] > array[randomIndexC]) {
    return "c is the middle value";
  } else {
    return "b is the middle value";
  }
}

This approach requires at least two and at most three comparisons. It deliberately ignores the possibility of two values being equal (as did your question): if this is important, the approach can be extended to check this also.

Tim
It's kind of ugly, and I think the OP was looking for an elegant solution. The trick is lots of people mistake fewer characters for more elegant, when in reality, more straightforward (this answer) is more readily optimizable by the compiler/virtual machine.
Karl
+2  A: 

If you must find one out of X values satisfying some criteria you have to at least compare that value to each of the X-1 others. For three values this means at least two comparisons. Since this is "find the value that is not the smallest and not the largest" you can get away with only two comparisons.

You should then concentrate on writing the code so you can very clearly see what goes on and keep it simple. Here this means nested if's. This will allow the JVM to optimize this comparison as much as possible at runtime.

See the solution provided by Tim (http://stackoverflow.com/questions/1582356/fastest-way-of-finding-the-middle-value-of-a-tripel/1582524#1582524) to see an example of this. The many code line does not necessarily turn out to be larger code than nested questionmark-colon's.

Thorbjørn Ravn Andersen
A: 

You might as well write this in the most straightforward, way. As you said, there are only six possibilities. No reasonable approach is going to be any faster or slower, so just go for something easy to read.

I'd use min() and max() for conciseness, but three nested if/thens would be just as good, I think.

Mark Bessey