Reputation: 1
Recently I did a test task in which it was necessary to calculate the median and other things. I wrote next function
function quartile(n) {
var observation = n * (len + 1) / 4 - 1;
if (n * (len + 1) % 4 === 0) {
return sortedSet[observation];
} else {
return Math.round((sortedSet[Math.floor(observation)] + (observation - Math.floor(observation)) *
(sortedSet[Math.ceil(observation)] - sortedSet[Math.floor(observation)])) * 10e3) / 10e3;
}
}
In feedback I get that median calculated in the wrong way. Now I can't figure out in which cases this function will behaves incorrectly. Can you explain what is wrong here?
P.S Use like this quartile(2)
Just sorting
I found what the problem was. I have used array.sort() and did not know that sorting in non natural order.
Upvotes: 0
Views: 154
Reputation: 12657
Well, your equation is wrong, and your condition too.
Your calculation of observation is off by 0.5 for the 1st and 3rd quartille, and by 1 for 0 and 4.
And your condition, better would have been if(observation%1 === 0)
or if(observation === Math.floor(observation))
Here a fixed version, and as mentioned in the comment, formatting/rounding float's is not the job of this function.
function quartile(n) {
//compute the position in the Array you want to fetch
//n==0 return the first, n == 4 returns the last item in the Array
var pos = n/4 * (len-1),
//separate the index ...
i = Math.floor(pos),
//and the fractional part
t = pos - i;
return t? //if there is a fractional part
//interpolate between the computed and the next index
(1-t) * sortedSet[i] + t * sortedSet[i+1]:
//otherwise return the value at the computed index
sortedSet[i];
}
Edit:
I took a look at wikipedia on that topic. God that's a weird, recursive, imo un-mathematical approach. And even worse, there's not one, there are three different definitions on how to calculate these quartiles, and they return different results.
//a utility, processes the part left <= indices < right
function _median(arr, left, right){
var i = (left+right)>>1;
return (right-left) & 1? arr[i]: .5 * (arr[i-1] + arr[i])
}
methods 1 and 2 are a more practical than mathematical approach, but through their recursive nature somehow quite straight forward
var method1 = {
Q1(arr){
return _median(arr, 0, arr.length>>1)
},
Q2(arr){
return _median(arr, 0, arr.length);
},
Q3(arr){
var len = arr.length;
return _median(arr, (len>>1)+(len&1), len);
}
}
var method2 = {
Q1(arr){
var len = arr.length;
return _median(arr, 0, (len>>1) + (len&1))
},
Q2(arr){
return _median(arr, 0, arr.length);
},
Q3(arr){
var len = arr.length;
return _median(arr, len>>1, len);
}
}
method 3 feels more like: "we can't agree wich method to use, 1 or 2. Let's take the average of both and finally close this topic"
var method3 = {
Q1(arr){
var len = arr.length,
r = (len >> 1) + (len&1),
i = r>>1;
return (r & 1)? arr[i]: .75 * arr[i-1] + .25*arr[i];
},
Q2(arr){
return _median(arr, 0, arr.length);
},
Q3(arr){
var len = arr.length,
l = len>>1,
i = (l+len)>>1;
return (len-l)&1? arr[i]: .25 * arr[i-1] + .75*arr[i];
}
}
Upvotes: 1