Determining optimal weight lifting bar configuration This program is meant to take two weights and return the best way to load a barbell for two people using different weights, so you don't have to keep changing out super heavy weights. I also made functionality for one person to use it to calculate the most efficient way to load the bar (least # of plates used).

If you notice, user_one() and user_two() are mostly the same code, with minor adjustments. perfect_combo() also shares some of the same.  I feel like there's a way to cut down on the code in this program.

weights=[100, 45, 35, 25, 10, 5, 2.5]
bar_weight = 45
prog_select = int(input('How many people on this bar?'
'(enter 1 or 2) '))
if prog_select == 1:
    target_weight = int(input('Enter weight: '))
elif prog_select == 2:
    target_weight = int(input('Enter first weight: '))
    target_weight1 = int(input('Enter second weight: '))


def user_one():
    nweights = []
    remaining = target_weight - bar_weight
    for  i, weight in enumerate(weights):
        if int(remaining / weight) % 2 == 0:
            nweights.append(int(remaining/ weight))
        else:
            nweights.append(int(remaining/ weight) - 1)
        remaining = remaining - nweights[i]*weights[i]
        if remaining == 0:
            break

    listweights=zip(nweights, weights)
    print(f'{bar_weight}lb bar')
    print(f'{target_weight}lbs')

    for weight in listweights:
        if weight[0] &gt;= 2:
            print(f"{weight[0]} | {weight[1]}'s")

    if remaining !=0:
        print(f'the correct weight combination cannot be found,'
              f'the remaining weight is: {remaining} pound')

def user_two():
    nweights = []
    remaining = target_weight1 - bar_weight
    for  i, weight in enumerate(weights):
        if int(remaining / weight) % 2 == 0:
            nweights.append(int(remaining/ weight))
        else:
            nweights.append(int(remaining/ weight) - 1)
        remaining = remaining - nweights[i]*weights[i]
        if remaining == 0:
            break

    listweights=zip(nweights, weights)
    if prog_select == 1:
        print(f'{target_weight1}lbs')
    else:
        print(f'{bar_weight}lb bar')
        print(f'{target_weight1}lbs')
    for weight in listweights:
        if weight[0] &gt;= 2:
            print(f"{weight[0]} | {weight[1]}'s")

    if remaining !=0:
        print(f'the correct weight combination cannot be found,'
              f'the remaining weight is: {remaining} pound')

def perfect_combo():
    nweights = []
    remaining = (target_weight - target_weight1)

    print("Add " + str(remaining) + "lbs for first weight")

    for  i, weight in enumerate(weights):
        if int(remaining / weight) % 2 == 0:
            nweights.append(int(remaining/ weight))
        else:
            nweights.append(int(remaining/ weight) - 1)
        remaining = remaining - nweights[i]*weights[i]
        if remaining == 0:
            break

    listweights=zip(nweights, weights)

    for weight in listweights:
        if weight[0] &gt;= 2:
            print(f"{weight[0]} | {weight[1]}'s")
    if remaining !=0:
        print(f'the correct weight combination cannot be found,'
              f'the remaining weight is: {remaining} pound')

# Run the program        

if prog_select == 1:
    user_one()
elif prog_select == 2:
    remaining = (target_weight - target_weight1)
    if remaining &gt; 99:
        print("You might want to use seperate bars...")
    else:
        user_two()
        perfect_combo()
else:
    print("That's too many peeps on one bar!")
The layout of your program is non-standard.  You have:


main program part 1
function definitions
main program part 2


Keep your main program together, don't split it up by adding functions in the middle, at least, not without a compelling reason.



There is minimal error checking in the program.  If the target weight is less than the bar weight, this is not reported.



    for  i, weight in enumerate(weights):
        if int(remaining / weight) % 2 == 0:
            nweights.append(int(remaining/ weight))
        else:
            nweights.append(int(remaining/ weight) - 1)
        remaining = remaining - nweights[i]*weights[i]
        if remaining == 0:
            break

    listweights=zip(nweights, weights)


This code is duplicated in user_one(), user_two() and perfect_combo().  You should move this into a function.

The code computes the number of a specific weight, and then adds the number to a list if it is even, or 1 less if it is odd.  Presumably, this is because the weights have to be added in pairs, one on each side of the bar, but this is never spelt out.

Finally, the list is zipped with the original list of weight options, to create pairs of counts and weights.

Let's create the function which does this computation, but let's make it more general.  You might have different bar types, say a light weight bar and a heavy weight bar.  The light weight bar would be lighter, and perhaps uses a different set of weights, but the algorithm would remain the same.  So the available weights should be passed in:

def weights_in_pairs(added_weight, available_weights):

    """Compute and return list of numbers and sizes of weights to
    form the desired additional weight for bar-bell.  Also returns any
    excess weight that could not be added."""

    weights = []
    remaining = added_weight
    for weight in available_weights:
        pairs = int(remaining / (2*weight))
        if pairs  &gt; 0:
            weights.append((pairs * 2, weight))
            remaining -= 2 * pairs * weight

    return weights, remaining


Instead of dealing with even/odd numbers, we double the weight and compute the number of pairs that can be added add.  Instead of zipping at the end, we add the (count, weight) tuple to the weights list; this allows us to omit the zero counts, to simplify printing later



    for weight in listweights:
        if weight[0] &gt;= 2:
            print(f"{weight[0]} | {weight[1]}'s")

    if remaining !=0:
        print(f'the correct weight combination cannot be found,'
              f'the remaining weight is: {remaining} pound')


This code is also duplicated between user_one(), user_two() and perfect_combo().  Again, we'll move this into a function.

def print_weights(weights, remaining):

    """Print out the weights to be added to the bar-bell,
    and the amount of un-added weight, if necessary."""

    for n, weight in weights:
        print(f"{n} | {weight}'s")

    if remaining != 0:
        print(f'the correct weight combination cannot be found,'
              f'the remaining weight is: {remaining} pound')


Note that the for loop immediate extracts the tuple into two variables, with the names n and weight.  This allows us to use these named quantities in the body of the loop, instead of indexes like weight[0] and weight[1] where the reader will have to look elsewhere to determine what was stored in the different indexes.

Also, since we skipped added the zero-count weights, we didn't need the if weight[0] &gt;= 2: statement.



We can combined the above two functions, to compute and print out the information displayed by user_one() and user_two().  Again, we'll pass in arguments for the desired weight, the bar weight, and the available weights:

def print_bar_configuration(target_weight, bar_weight, weights):

    """Compute and print bar-bell configuration for given weights."""

    listweights, remaining = weights_in_pairs(target_weight - bar_weight, weights)

    print(f'{bar_weight}lb bar')
    print(f'{target_weight}lbs')

    print_weights(listweights, remaining)




With the above functions, perfect_combo() can be simplified:

def perfect_combo(heavy_weight, light_weight):

    """Compute and print optimal additional weight configuration."""

    weight_difference = heavy_weight - light_weight

    print(f"Add {weight_difference}lbs for heavier weight")

    listweights, remaining = weights_in_pairs(weight_difference, weights)
    print_weights(listweights, remaining)


Note: This raise the question of "what happens if the first weight was lighter than the second?"  Perhaps your program should mention that requirement, and test for it.  Or adapt the reversed data input.



Using the above functions, we can simplify the main program, moving and combining the code at the top with the code at the bottom.  Also, renaming odd variables like target_weight1 to something more meaningful:

if prog_select == 1:
    target_weight = int(input('Enter weight: '))
    print_bar_configuration(target_weight, bar_weight, weights)
elif prog_select == 2:
    heavy_weight = int(input('Enter heavier weight: '))
    light_weight = int(input('Enter lighter weight: '))

    if heavy_weight - light_weight &gt; 99:
        print("You might want to use separate bars...")
    else:
        print_bar_configuration(light_weight, bar_weight, weights)
        perfect_combo(heavy_weight, light_weight)
else:
    print("That's too many peeps on one bar!")