Matching socks from a bag of socks I was reading the book Algortihms to Live By and was inspired by it to take a shot at simulating How to pair socks from a pile? (sans the efficiently part at the moment).

import random
from operator import add


def get_pair_of_socks(num_of_socks):
    return random.sample(range(num_of_socks), num_of_socks)


def index_to_pull_sock_from(bag_of_socks: list):
    return random.randint(a=0, b=len(bag_of_socks) - 1)


def attempt_counts_matching_socks(num_of_socks_to_consider):
    # Keep attempt counts in this list.
    attempt_counts = []

    # Generate pairs of random socks.
    socks = get_pair_of_socks(num_of_socks_to_consider) + get_pair_of_socks(num_of_socks_to_consider)

    while len(socks) != 0:
        # Pick one pair from the bag..
        first_pair = socks.pop(index_to_pull_sock_from(socks))

        # Pick a second pair..
        random_pick = index_to_pull_sock_from(socks)
        second_pair = socks[random_pick]

        # We did an attempt..
        attempt_count = 1

        # If they matched, perfect. We will never enter this block.
        # Otherwise loop until you do find the match..
        while second_pair != first_pair:
            # Increment the attempt_count whenever you loop..
            attempt_count = attempt_count + 1
            random_pick = index_to_pull_sock_from(socks)
            second_pair = socks[random_pick]

        # Remove the second matching pair from the bag..
        socks.pop(random_pick)

        # Keep the number of attempts it took you to find the second pair..
        attempt_counts.append(attempt_count)

    return attempt_counts


num_of_iterations = 1000
pair_of_socks = 10

# Initalise a list of length `pair_of_socks`
attempt_counts_so_far = [0] * pair_of_socks

for _ in range(num_of_iterations):
    # Get attempt counts for 1 iteration..
    attempt_counts_single_iteration = attempt_counts_matching_socks(pair_of_socks)

    # Add the attempt counts aligned by index. We will be dividing by the total number of iterations later for averages.
    attempt_counts_so_far = list(map(add, attempt_counts_so_far, attempt_counts_single_iteration))

average_takes = list(map(lambda x: x / num_of_iterations, attempt_counts_so_far))
print(average_takes)
# [18.205, 16.967, 14.659, 12.82, 11.686, 9.444, 7.238, 4.854, 2.984, 1.0]
Your get_pair_of_socks seems to be initializing a pile of socks, so you have the wrong name. 

If I understand things correctly, you initialize a pile of "left" socks, then initialize a pile of "right" socks (socks don't have left and right, but the labels make it easier to keep track of what's going on), and then put the pile of "left" socks on top of the "right" pile. So each half of the final pile has only one copy of each sock pair. This is an odd situation to be simulating. I recommend initializing the pile in one go with random.sample(list(range(number_of_socks_to_consider))*2,2*number_of_socks_to_consider).

I think you could just take the sock on the top of the pile without affecting the results, rather than the complicated pop statement you're currently using. (A random element from a random permuted set isn't any more random than the first element from a randomly permuted set).

first_pair seems to be the first sock in the attempted pair, while second_pair is the  second sock, which, again, is poor naming (perhaps you are confusing "pair" with "partner").

I don't think you're following the algorithm describes in that link: that involves taking a sock, then taking the rest of the socks in order, while you are taking a sock, then checking the remaining socks with replacement, which again is making it take longer.

You don't need a separate case to handle the first sock you try to pair with the sock you picked. You can just do this:

    first_pair = socks.pop(index_to_pull_sock_from(socks))
    attempt_count = 0
    while True:
        attempt_count = attempt_count + 1
        random_pick = index_to_pull_sock_from(socks)
        second_pair = socks[random_pick]
        if second_pair == first_pair:
                break