Reputation: 2191
I have built a function that allows you to pass through an array and it successfully returns the second highest and second lowest numbers. However, I'm new to error handling and don't understand why this fails:
getNos([5,"5",8]);
It works correctly when passing in getNos([5,5,8])
; or passing arrays like getNos(["5",8]);
.
Can someone explain what's happening here and how to fix it? Thanks for any help here - the function code is below:
function getNos(arr){
if (!Array.isArray(arr) || arr.length == 0 || arr.length == 1 || (arr.every(c => !isNaN(c)) == false)) {
throw 'Invalid Input';
} else {
var result;
var uniqueVals = Array.from(new Set(arr));
var highest = highestVal(arr);
var lowest = lowestVal(arr);
if (uniqueVals.length == 1) {
result = arr[0] + " " + arr[0];
} else if (arr.length == 2 || uniqueVals.length == 2) {
result = highest + " " + lowest;
} else {
arr = arr.filter(item => ((item !== highest) && (item !== lowest)));
var secondHighest = highestVal(arr);
var secondLowest = lowestVal(arr);
if (arr.length == 1) {
arr = arr.slice(arr.indexOf(secondHighest));
result = highestVal(arr);
} else {
result = secondLowest + " " + secondHighest;
}
}
return result;
}
function highestVal(a) { return a.reduce((a, b) => a > b ? a : b ) };
function lowestVal(a) { return a.reduce((a, b) => a < b ? a : b ) };
}
Upvotes: 0
Views: 67
Reputation: 96
The function does not fail in the sense that it throws an error. For these types of questions please add an example of "expected results".
When you compare strings and numbers in JavaScript, you are relying on implicit coercion to take care of the comparison. In this case it won't throw and error and break anything, it is fine as JavaScript will convert your string to a number and compare (unless its a strict equality === which checks type as well).
Should the result be based off what was passed in? Or after the input has been filtered for numbers only. Or if the input can be converted to valid numbers?
In the case of filter for valid numbers. Filter the input as follows...
arr = arr.filter(data => typeof data === 'number')
In the case of converting values to a number and removing those that cannot be converted...
arr = arr.reduce(((acc, el) => {
const num = Number(el);
if (!Number.isNaN(num)) acc.push(num);
return acc;
}), []);
Upvotes: 1
Reputation: 171690
Simple fix would be map the values to numbers before creating the set to avoid having the same numeric values as both string and number in the set
Change
var uniqueVals = Array.from(new Set(arr));
To
var uniqueVals = Array.from(new Set(arr.map(Number)));
Upvotes: 1
Reputation: 3525
Follow carefully the logic var uniqueVals = Array.from(new Set(arr))
. What will this line return when you have arrays such as [5,"5",8]
vs [5,5,8]
vs ["5", 8]
?
A Set
stores unique value of a type
. "5"
is of type string
whereas 5 is of type number
. The highestVal
and lowestVal
functions can compare "5"
and 8
, no problem, but since an array could include either a string
or number
for either 5 or 8 as well, then you will get funny values being returned.
To fix this, before passing arr
to the Set
, you need to convert all values to a single type, preferably number
.
let numberArr = arr.map(el=>+el)
is one way of doing that, but you may want better data validation than that.
Upvotes: 3