Search code examples
pythonlistconditional-statementstupleslogic

Categorize a tuple from a list of tuples based on conditional statements


I hope you can help me with my logic conditions that i have been struggling with.

I have a list of tuples in the following format:

[(2, 1), (2, 2), (3, 1)]

Each tuple (person) contains two numbers. The first number is e.g. number of apples (a) and the second number is the number of bananas (b).

What I want is to find two tuples in the list of tuples and characterize them into two categories, let us say evil and good.

So the rule are in general: The person with most apples is good if the person has no bananas The person with most bananas is evil if the person has no apples

Example 1:

[(3, 0), (2, 1), (0, 3)]

Result

  • tuple with index 0 is good as it has the most apples
  • tuple with index 2 is evil as it has the most bananas

If a person has both apples and bananas, then I want the following: The person is good with the most apples and fewest bananas. However, if there is a person who has fewer bananas than the person with the most apples, then this person is the good person, as in these examples:

Example 2:

[(1, 0), (2, 1)]

Result

  • tuple with index 0 is good as it has an apple
  • tuple with index 1 is evil as it has a banana

Example 3:

[(2, 1), (2, 2), (3, 1)]

Result

  • tuple with index 1 is evil as it has the most bananas
  • tuple with index 2 has the good as it has the most apples and less than most bananas

Example 4:

[(2, 1), (2, 2), (2, 2)]

Result

  • tuple with index 1 and 2 is evil as it has the most bananas
  • tuple with index 0 has the good as it has the most apples and less than most bananas

What I have tried so far is to split the list of tuples into two lists, e.g.:

  • len_apples_per_person = (2, 2, 2)
  • len_bananas_per_person = (1, 2, 2)

But as the relationship between apples and bananas determines if a person is good or evil I don’t think it is the right way.

If a tuple in a list of tuples has (0,0) is should be ignored. I have a workaround for that but it is a bit clumsy so if anyone could come up with an idea on how to solve my issues, I will be so happy.

Below is a code example. I realize that I should have the min an max values outside the loop for efficiency and it doesn't change over. Anyway, this code example does not catch everything.

#Here we check which person is the good and evil
for idx in range(len(len_apples_per_person)):
    if len_apples_per_person[idx] == min(len_apples_per_person) and 
       len_bananas_per_person[idx]!=0:
        idx_evil = idx
    if len_apples_per_person[idx] ==  max(len_apples_per_person):
        idx_good = idx

print(idx_good, idx_evil)

I hope someone can help me with the logic.


Solution

  • I managed to solve my own question after a very long time.

    I ended up looking at the relationship between the apples and bananas which simplified the code quite a lot.

    However, there was still some exceptions where I needed to add more code to get the correct index.

    Below is a working code example where I go through 9 examples.

    def retrieve_good_evil_idx(listoftuples=None):
    """
    Retrieves the index of the good and evil in a list of tuples
    
    """
    start_apple_to_banana = -1
    start_banana_to_apple = -1
    store_banana = 0
    store_apple = 0
    
    for idx, (apple, banana) in enumerate(listoftuples):
        try:
            apple_to_banana = apple/banana
            banana_to_apple = banana/apple
        except ZeroDivisionError:
            apple_to_banana = apple
            banana_to_apple = banana
    
        if apple_to_banana > start_apple_to_banana:
            idx_good = idx
            if banana_to_apple > start_banana_to_apple and idx != 0:
                idx_good = idx-1
            if store_apple == 0 and idx != 0:
                idx_good = idx
    
        if banana_to_apple > start_banana_to_apple:
            idx_evil = idx
            if store_apple == 0 and idx != 0:
                idx_evil = idx-1
        
        start_apple_to_banana = apple_to_banana
        start_banana_to_apple = banana_to_apple
        store_apple = apple
        store_banana = banana
        
    return idx_good, idx_evil
    
    apples_bananas = (
                [(2, 1), (2, 2), (3, 1)], 
                [(3, 0), (2, 1), (0, 3)], 
                [(1, 0), (2, 1)], 
                [(2, 1), (2, 2), (3, 1)], 
                [(2, 1), (2, 2), (2, 2)],
                [(1, 1), (1, 1)],
                [(1, 2), (1, 0)],
                [(0, 1), (1, 2)],
                [(1, 2), (2, 1)]
                )
    print('(good index, evil index)')
    for i in apples_bananas:
        print(retrieve_good_evil_idx(listoftuples=i))
    
    (good index, evil index)
    (2, 1)
    (0, 2)
    (0, 1)
    (2, 1)
    (0, 1)
    (0, 0)
    (1, 0)
    (1, 0)
    (1, 0)
    

    I know the code is suboptimal so if you would help me optimizing the code and come up with feedback, I would be more than happy.