Creating a list of new areas for patches of conserved land within a watershed I'm writing code to create a list of new areas for patches of conserved land within a watershed based on the current size distribution of conserved land patches that are in the watershed now. 

I'm generating a new random area based on a normal probability density function fitted to the log-transformed distribution of the sizes of currently conserved land. Then I have a list of the areas of tax parcels in the region, and I want to randomly grab a tax parcel that is within ± 10% of the randomly generated area. The loop will continue until I've generated a total 4,735 hectares of new areas for conservation.

The code works, and runs very quickly if I lower the threshold for total new conserved area to ~500 hectares. However, for my current endpoint (4,735 new hectares), it runs so slowly that I haven't actually ever run it all the way through (waited an hour+). Any ideas on how I can streamline this code to get it to run faster are greatly appreciated!

# Set endpoint of total new area
new_cons_area = 4735.44

# Get new random areas until they total the new_cons_area
sum_rand_area = 0
new_rand_area = []
rand_sizes = []
index_list = []
while sum_rand_area &lt; new_cons_area:
    # Get new random size based on current distribution of sizes of conservation patches
    new_log_size = np.random.normal(param_log[0],param_log[1],1)
    # Transform back to actual area
    new_size = np.e**new_log_size[0]
    # Set buffer boundaries
    min_size = new_size * 0.9
    max_size = new_size * 1.1
    # Get length of new_rand_area list
    current_length = len(new_rand_area)
    # Set up loop to grab sizes from the current list of tax parcels suitable for conservation
    if new_size &gt;= 3.33:
        # Run this loop until a new size is added to the list of new random areas
        while len(new_rand_area) == current_length:
            # Grab a random index from the list of parcel areas
            rand_index = random.randrange(len(parcel_areas)-1)
            # See if the parcel area associated with the random index matches the randomly generated size
            if min_size &lt;= parcel_areas[rand_index] &lt;= max_size:
                # If criteria is met, add the randomly generated size to a list
                rand_sizes.append(int(new_size))
                # Add the randomly generated index to list so you can grab the object ids in the next step
                index_list.append(rand_index)
                # Add the actual tax parcel area to a list
                new_rand_area.append(parcel_areas[rand_index])
                # Add the area to the total area of new land to be conserved
                sum_rand_area += parcel_areas[rand_index]
The problem is that random.randrange(len(parcel_areas)-1) most of the times returns an area which fails the min_size &lt;= parcel_areas[rand_index] &lt;= max_size test. Therefore it is logical to restrict the random selection to the set of areas which satisfy the requirements beforehand, and eliminate the inner loop completely.

Sort the list of areas by size. Once you determined min_size and max_size, find corresponding bounds (with binary search), and select randomly within these bounds.