pythonpython-3.xlistgenetic

Remove (or replace) items in a multi-level list based on one of the parameters inside


population=[[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [4], [0]],
[[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1], [3], [1]],
[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [4], [2]],
[[1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0], [1], [3]]]    

selected_chromosomes=[[[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [5], [2]],
[[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [3], [0]]]

child1=[0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0]
child2=[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1]   



def PopulationAdjustment(population, selected_chromosomes):
    for game in range(0, len(selected_chromosomes)):
        if game in selected_chromosomes[game][2]==game in population[game][2]: 
            population.remove(game)
    return population  

So the objective here is to replace the parents for the children in a population (list), my approach was to delete the parents then append the children, based on the same counter. The structure of the list is [[chromosome],[fitness],[counter]], however they are not exactly the same since I manipulated the fitness during the selection to avoid 0 probabilities.

I am trying to index the items that have the same counter and delete them from the list, then the next step would be just to append the children.

Ive been trying some different ways but I couldnt get it working properly, any thoughts on how to fix that? Also, if there is a way of replacing them directly by the children without having to perform 2 steps (remove and append) it would be aslo very welcome. Thanks!!


Solution

  • You said "I am trying to index the items that have the same counter and delete them from the list". While that's possible, it's easier (and faster) to just build a new list that contains the chromosomes that you want to keep, unless population is huge.

    We first scan the selected_chromosomes to extract their counter numbers into a set so we can look them up quickly.

    population=[
        [[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [4], [0]],
        [[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1], [3], [1]],
        [[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [4], [2]],
        [[1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0], [1], [3]],
    ]
    
    selected_chromosomes=[
        [[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [5], [2]],
        [[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [3], [0]],
    ]
    
    def population_adjustment(population, selected_chromosomes):
        # Create a set of the counter numbers to remove
        drop = {u[-1][0] for u in selected_chromosomes}
    
        # Copy the wanted chromosomes to a new list
        return [u for u in population if u[-1][0] not in drop]
    
    new_pop = population_adjustment(population, selected_chromosomes)
    for row in new_pop:
        print(row)
    

    output

    [[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1], [3], [1]]
    [[1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0], [1], [3]]
    

    If the population list is huge, or you have some other reason to keep the original list (eg, there are multiple references to it in various places), here's how to delete the unwanted lists. We have to be careful, though. Removing items from a list that you're iterating over is dangerous, since removal disturbs the indices of the remaining list items, as shown here. It's a bit like cutting a tree branch that you're sitting on. If you cut in the wrong place, Bad Things happen. ;) The simplest way is to iterate over the list in reverse.

    population=[
        [[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [4], [0]],
        [[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1], [3], [1]],
        [[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [4], [2]],
        [[1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0], [1], [3]],
    ]
    
    selected_chromosomes=[
        [[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0], [5], [2]],
        [[0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [3], [0]],
    ]
    
    def population_adjustment(population, selected_chromosomes):
        # Create a set of the counter numbers to remove
        drop = {u[-1][0] for u in selected_chromosomes}
    
        # Iterate backwards over population so we can safely delete sublists
        for i in range(len(population)-1, -1, -1):
            k = population[i][-1][0]
            if k in drop:
               del population[i] 
    
        # Since we mutate `population` we should return `None`, as is conventional in Python.
        # This return statement isn't necessary, since `None` is the default return value,
        # but it's nice to be explicit
        return None
    
    population_adjustment(population, selected_chromosomes)
    for row in population:
        print(row)
    

    This code produces the same output as the previous version, so I won't repeat it.