When finding the best ensemble, using "find_best_ensemble," in the event of a tie, we break it by looking at
    enrichment factors at successively larger FPF values, beginning with the smallest FPF not trained on.
    :param sorted_list:
    :param results:
    :return:

def tie_break(sorted_list, results, prop_key, ndecoys):
    """
    When finding the best ensemble, using "find_best_ensemble," in the event of a tie, we break it by looking at
    enrichment factors at successively larger FPF values, beginning with the smallest FPF not trained on.
    :param sorted_list:
    :param results:
    :return:
    """

    # Generate a list of the number of decoys that correspond to the FPF
    # values at which enrichment factors were determined, not including ndecoys, the training value
    ndecoys_list = sorted([x for x in list(results.values())[0].ef.keys() if x != ndecoys])

    # break the tie the ensemble that maximizes the enrichment factor at a given FPF (that corresponds to ndecoys)
    if prop_key == 'ef':
        index = 0
        while index < len(ndecoys_list) and sorted_list[0][1].get_prop(ndecoys_list[index], prop_key) == \
                sorted_list[1][1].get_prop(ndecoys_list[index], prop_key):
            sorted_list = sorted(results.items(), key=lambda r: (r[1].get_prop(ndecoys, prop_key),
                                                                 r[1].get_prop(ndecoys_list[index], 'ef')),
                                 reverse=True)
            index += 1
    # break the tie if the ensemble that maximizes the auc is desired
    elif prop_key == 'auc':
        index = 0
        while sorted_list[0][1].get_prop(prop_key) == sorted_list[1][1].get_prop(prop_key) \
                and index < len(ndecoys_list):
            sorted_list = sorted(results.items(), key = lambda x: (x[1].get_prop(prop_key),
                                                                   x[1].get_prop(ndecoys_list[index])))
            index += 1

    return sorted_list