Picking 2 Socks At Random
Amazon used to ask this problem as part of their interview:
A drawer contains 12 identical black socks and 12 identical white socks. If you pick 2 socks at random, what is the probability of getting a matching pair?
Think about it for a few minutes before scrolling down to read this further.
Ready?
My immediate reaction was “11/23”. But the question is supposed to be hard, which is why I assumed my answer was completely wrong. Well, maybe it wasn’t? There is only one way to verify.
It takes less than a second to do this experiment a million times in a row. So let’s do that.
Apparently, the most common wrong answer is 50%.1 The reason for this mistake is that people fail to account for the second draw’s dependency on the first. After one sock is drawn, the probabilities shift because the composition of the drawer changes.
Let’s start. Here is our drawer filled with socks.
const drawer = [
'⚪️', '⚪️', '⚪️', '⚪️', '⚪️', '⚪️',
'⚪️', '⚪️', '⚪️', '⚪️', '⚪️', '⚪️',
'⚫️', '⚫️', '⚫️', '⚫️', '⚫️', '⚫️',
'⚫️', '⚫️', '⚫️', '⚫️', '⚫️', '⚫️',
]
We have exactly 12 white and 12 black socks in our array. Now, we need to randomly draw two socks from here.
const getRandomInt = max => Math.floor(Math.random() * max)
This function will return a random integer less than the max
value it takes in. Note that max
is non-inclusive so we can pass in the array length. In JavaScript, array indexing starts at 0, so for an array with 24 elements, the indexes range from 0 to 23.
We can use our function to draw two socks.
const firstDrawIndex = getRandomInt(24)
const [firstSock] = drawer.splice(firstDrawIndex, 1)
const secondDrawIndex = getRandomInt(23)
const [secondSock] = drawer.splice(secondDrawIndex, 1)
return firstSock === secondSock
splice
will remove the sock from the array and return the resulting item that was just removed from the array. It will return an array with a single item, so we just need to pick the first element.
We have a pair now. Let’s just check if these two socks are the same color.
firstSock === secondSock
Whenever they are equal, we have a matching pair. Whenever they’re not, we have a non-matching pair.
Let’s move the logic we have so far into a function drawPair
and run it a million times.
And let’s keep counting the result while doing that.
let matchingCount = 0
let nonMatchingCount = 0
for (let i = 0; i < 1000000; i++) {
drawPair() ? matchingCount++ : nonMatchingCount++
}
const probability = Number(
matchingCount / (matchingCount + nonMatchingCount) * 100)
+ '%'
Have fun:
We should be getting results around %47.8, which is 11/23. Here is the actual number in a higher precision:
(11/23) * 100 = 47.82608695652174%
Or maybe it’s the perfect answer. Things either happen or they don’t. ↩