Search code examples
pythonloopsprobabilitypython-itertoolscombinatorics

Removing a combination from a list given criteria (Python)


I have a problem whereby if I have a list as follows.

  1. I compare in a pairwise manner (I.e. ["R",1], ["A",1]) if both share the same number but different letter.
  2. I generate a probability: either 1, or both are removed from the list.
  3. If any or both are removed, I want to make sure that I don't iterate over a pair wise combination that has been previously removed. For eg. if I remove a_list[1], then the pair a_list[1] and a_list[4] can never be considered.

a_list = [["R",1], ["A",1], ["R",2], ["A",2], ["R", 1]]

Note that the context of this problem is to simulate a species simulation if two different species are in the same location (indicated by 1), then they either die or stay alive.

Another example of what I want: If I set the rule that I kill the second person in the pair, then for each combination of (["R",1], ["A",1]), (["A",1], ["R", 1] ), (["R",2], ["A",2]) >> then I kill what's been bolded. But ideally we don't even consider the second pair as [A, 1] was killed anyways in that first combo.

Many thanks!

My thinking is to add some continue line if the element has been removed from the original list however in the case below, I get the error: "list.remove(x): x not in list"

This is what I have tried so far:

a_list = [["R",1], ["A",1], ["R",2], ["S",2], ["R", 1]]


for a, b in itertools.combinations(a_list[:], 2):
    if a[0]!=b[0] and a[1]==b[1]:
        print(a,b)
        a_prob=np.random.choice([0,1], p=[0.5,0.5])
        b_prob=np.random.choice([0,1], p=[0.5,0.5])
        if a_prob==1:
            print("a alive",a_prob)
        else:
            if a_prob==0: 
                a_list.remove(a)
                print("a dead",a_prob)
                
        
        if b_prob==1:
            print("b alive",b_prob)
        else:
            if b_prob==0: 
                a_list.remove(b)
                print("b dead",b_prob)
        

Solution

  • the problem with your code is that it is not updating the itertools.combinations(a_list[:], 2) so once you delete a value you can still iterate over a different combination containing that value

    I have enumerated your original list (since a value can occur more than once like ["R", 1]) and then created a list for itertools.combinations(a_list[:], 2) and also created a function to properly delete a value from that list

    a_list = [["R", 1], ["A", 1], ["R", 2], ["S", 2], ["R", 1]]
    a_list_2 = list(enumerate(a_list))
    a_combinations = list(itertools.combinations(a_list_2, 2))
    
    
    def a_remove_element(x):
        for i in a_combinations[:]:
            if i[0][0] == x or i[1][0] == x:
                a_combinations.remove(i)
    
    
    for a, b in a_combinations:
        if a[1][0] != b[1][0] and a[1][1] == b[1][1]:
            print(a, b)
            a_prob, b_prob = np.random.choice([0, 1], size=2)
            if a_prob:
                print("a alive", a_prob)
            else:
                a_remove_element(a[0])
                print("a dead", a_prob)
    
            if b_prob:
                print("b alive", b_prob)
            else:
                a_remove_element(b[0])
                print("b dead", b_prob)