Background
For a technical interview I was tasked with implementing a missing algorithm in JavaScript. The interviewer supplied me with some code and 18 failing unit tests that once the algorithm was successfully implemented would pass. I'm sure there is a more efficient way to have solved this problem as I tried a few different approaches during my allotted time. This way is the first way that I got to work, which for the technical test was enough but I'd like to know a better way of solving the problem.
Problem
Work out if the cards in a poker hand form a straight. (I've already ordered the hand in ascending order.)
My Solution
PokerHand.prototype._check_straight_function = function(arr) {
var isStraight = false;
for (var j = i = 4; i >= 0 && j > 1; i--)
if (arr[i].value() - 1 == arr[--j].value()) {
isStraight = true;
} else {
isStraight = false;
}
};
return isStraight;
};
Other approaches
Things I didn't get working that I think might work faster, I'd really appreciate if someone could talk me through a working version of the below approach(es) and help me understand which is the fastest to evaluate.
- recursive use of
arr.pop().value - 1 == arr.pop().value()
filter
the array to create a new array that contains only values where the next index (arr[++i])
is the current index + 1 and then see if the new array is the same length.- a
for loop
with abreak / continue
to short circuit as soon as the straight ends.
Background
For a technical interview I was tasked with implementing a missing algorithm in JavaScript. The interviewer supplied me with some code and 18 failing unit tests that once the algorithm was successfully implemented would pass. I'm sure there is a more efficient way to have solved this problem as I tried a few different approaches during my allotted time. This way is the first way that I got to work, which for the technical test was enough but I'd like to know a better way of solving the problem.
Problem
Work out if the cards in a poker hand form a straight. (I've already ordered the hand in ascending order.)
My Solution
PokerHand.prototype._check_straight_function = function(arr) {
var isStraight = false;
for (var j = i = 4; i >= 0 && j > 1; i--)
if (arr[i].value() - 1 == arr[--j].value()) {
isStraight = true;
} else {
isStraight = false;
}
};
return isStraight;
};
Other approaches
Things I didn't get working that I think might work faster, I'd really appreciate if someone could talk me through a working version of the below approach(es) and help me understand which is the fastest to evaluate.
- recursive use of
arr.pop().value - 1 == arr.pop().value()
filter
the array to create a new array that contains only values where the next index (arr[++i])
is the current index + 1 and then see if the new array is the same length.- a
for loop
with abreak / continue
to short circuit as soon as the straight ends.
- are the cards in the hand sorted? – stinepike Commented Oct 7, 2015 at 5:09
- 1 Looks like your question might be a better fit for codereview.stackexchange. – Spencer Wieczorek Commented Oct 7, 2015 at 5:09
- @StinePike yes, per the line (I've already sorted the cards in ascending order) – Luke Commented Oct 7, 2015 at 5:11
- 1 The code is incorrect because it will assign isStraight (or clear it) only for the given pair being checked. Thus the "last pair" incorrectly determines the result. – user2864740 Commented Oct 7, 2015 at 5:16
- 1 Because the array is already ordered, we know that a necessary condition to have a straight is that the difference between the first card value and the last card value is exactly four. You may have a global performance gain by adding this test if you have a large number of arrays to check and most of them are not passing it. Side note : if we know that all cards have distinct values, it bees a sufficient condition. – Arnauld Commented Oct 7, 2015 at 16:24
6 Answers
Reset to default 2There's no need to assign a variable isStraight at all.
PokerHand.prototype._check_straight_function = function(arr) {
for (var i = i = 4; i++) {
if (arr[i].value() - 1 != arr[i-1].value()) {
return false;
}
};
return true;
};
Just throwing it out there, I think this one does it with the least amount of lines (3), whether or not that is "better" is subjective as it is probably less clear
var last = arr.pop().value(), popped;
while ((popped = arr.pop().value()) === --last);
return popped === undefined;
The [original] code is incorrect because it will assign isStraight
(or clear it) only for the given pair being checked. Thus the "last pair" incorrectly determines the result.
In my book the "better way", is to keep it clean:
for (var i = 0; i < 4; i++) {
var a = arr[i]; // arr[0..3]
var b = arr[i+1]; // arr[1..4]
if (!(a.value() + 1 == b.value())) {
return false; // Not sequential
}
};
return true;
If a zip
higher-order function is available this could be reduced as a variation of
arr.zip(function (a, b) { return [a.value(), b.value()] })
.every(function (x) { return x[0] + 1 === x[1] })
but zip
is not standard.
here is a similar code with some minor optimization ( in java,, check the algorithm)
boolean isStraight = true;
for (int i = 0; i < 4; i++) {
if (arr[i] + 1 != arr[i+1]) {
isStraight = false;
break;
}
};
Well, this is maybe a tiny bit tidier. I don't see a Ninja way ;( As far as paring the solutions -- I'm an employer, and for my part, I'd prefer the answer which was clear and elegant over one which was a few nanoseconds faster :)
for (var i = 0; i < 5; i++) {
if (a[i].value() != i + a[0].value())
return false;
}
return true;
here is another way
var isOrdered = true;
[5, 6, 8, 9].sort(function(a, b) {
(b - a != 1) ? isOrdered = false: true;
});
alert(isOrdered);
DEMO