python-3.xlistnested-listscrossover

How to perform crossover of two nested lists without changing the contents inside their sub lists in Python?


I have two nested lists

parent_M: [[[5222, 'BSC2', 'ST6'], ['LR1'], ['FTM3']], [[4222, 'BSC1', 'ST6'], ['LH2'], ['TTM3']], [[4222, 'BSC1', 'ST6'], ['CR1'], ['MTM3']], [[4202, 'BSC1', 'ST3'], ['LH2'], ['TTM2']], [[6008, 'BSC3', 'ST1'], ['LH2'], ['FTM1']], [[4210, 'BSC1', 'ST1'], ['LH1'], ['TTM2']], [[6008, 'BSC3', 'ST1'], ['LH2'], ['THTM3']], [[3225, 'BSC1', 'ST6'], ['LH2'], ['MTM2']], [[4210, 'BSC1', 'ST1'], ['LR1'], ['THTM3']], [[5225, 'BSC2', 'ST6'], ['LH2'], ['WTM1']], [[5019, 'BSC2', 'ST3'], ['CR1'], ['WTM2']], [[5019, 'BSC2', 'ST3'], ['LB1'], ['THTM1']], [[4220, 'BSC2', 'ST5'], ['LB1'], ['MTM1']], [[6008, 'BSC3', 'ST1'], ['LH2'], ['FTM5']], [[5019, 'BSC2', 'ST3'], ['LH1'], ['FTM1']]]
parent_F: [[[4202, 'BSC1', 'ST3'], ['CR1'], ['THTM2']], [[5225, 'BSC2', 'ST6'], ['LH2'], ['MTM2']], [[5225, 'BSC2', 'ST6'], ['LB1'], ['FTM1']], [[5222, 'BSC2', 'ST6'], ['CR1'], ['WTM1']], [[4202, 'BSC1', 'ST3'], ['LH1'], ['THTM2']], [[4202, 'BSC1', 'ST3'], ['LR1'], ['MTM1']], [[4227, 'BSC1', 'ST4'], ['LH2'], ['TTM1']], [[4222, 'BSC1', 'ST6'], ['LB1'], ['WTM3']], [[4210, 'BSC1', 'ST1'], ['LH1'], ['THTM1']], [[5227, 'BSC2', 'ST8'], ['LB1'], ['WTM2']], [[6226, 'BSC3', 'ST6'], ['LB1'], ['THTM1']], [[6226, 'BSC3', 'ST6'], ['CR1'], ['THTM2']], [[3225, 'BSC1', 'ST6'], ['LB1'], ['THTM2']], [[4202, 'BSC1', 'ST3'], ['LH2'], ['THTM1']], [[4222, 'BSC1', 'ST6'], ['LH2'], ['MTM3']]]

What I expect is to swap random sub lists from Parent 1 with the other sub lists at the same position in Parent 2 without changing the contents inside them

Expectation example:

Children 1: [[[5222, 'BSC2', 'ST6'], ['CR1'], ['FTM3']], [[5225, 'BSC2', 'ST6'], ['LH2'], ['MTM2']], [[4222, 'BSC1', 'ST6'], ['LB1'], ['FTM1']], [[4202, 'BSC1', 'ST3'], ['LH2']…
Children 2: [[[4202, 'BSC1', 'ST3'], ['LR1'], ['THTM2']], [[4222, 'BSC1', 'ST6'], ['LH2'], ['TTM3']], [[5225, 'BSC2', 'ST6'], ['CR1'], ['MTM3']], [[5222, 'BSC2', 'ST6'], ['CR1']…

This is what I tried (convert each element into string):

    # Crossover Stage
    def crossover_Chromo(self, population):

        c1 = []
        c2 = []

        # convert nested lists to one list
        merged_p1 = list(itertools.chain.from_iterable(population[0]))
        merged_p2 = list(itertools.chain.from_iterable(population[1]))

        parent1 = list(itertools.chain.from_iterable(merged_p1))
        # parent_1_Chromo = ''.join(map(str, parent1))


        parent2 = list(itertools.chain.from_iterable(merged_p2))
        # parent_2_Chromo = ''.join(map(str, parent2))

        parent1 = [str(r) for r in parent1]
        parent2 = [str(r) for r in parent2]

        print("parent_M:", parent1)
        print("parent_F:", parent2)

output:

parent_M: ['5222', 'BSC2', 'ST6', 'LR1', 'FTM3', '4222', 'BSC1', 'ST6', 'LH2', 'TTM3', '4222', 'BSC1', 'ST6', 'CR1', 'MTM3', '4202', 'BSC1', 'ST3', 'LH2', 'TTM2', '6008', 'BSC3', 'ST1', 'LH2', 'FTM1', '4210', 'BSC1', 'ST1', 'LH1', 'TTM2', '6008', 'BSC3', 'ST1', 'LH2', 'THTM3', '3225', 'BSC1', 'ST6', 'LH2', 'MTM2', '4210', 'BSC1', 'ST1', 'LR1', 'THTM3', '5225', 'BSC2', 'ST6', 'LH2', 'WTM1', '5019', 'BSC2', 'ST3', 'CR1', 'WTM2', '5019', 'BSC2', 'ST3', 'LB1', 'THTM1', '4220', 'BSC2', 'ST5', 'LB1', 'MTM1', '6008', 'BSC3', 'ST1', 'LH2', 'FTM5', '5019', 'BSC2', 'ST3', 'LH1', 'FTM1']
parent_F: ['4202', 'BSC1', 'ST3', 'CR1', 'THTM2', '5225', 'BSC2', 'ST6', 'LH2', 'MTM2', '5225', 'BSC2', 'ST6', 'LB1', 'FTM1', '5222', 'BSC2', 'ST6', 'CR1', 'WTM1', '4202', 'BSC1', 'ST3', 'LH1', 'THTM2', '4202', 'BSC1', 'ST3', 'LR1', 'MTM1', '4227', 'BSC1', 'ST4', 'LH2', 'TTM1', '4222', 'BSC1', 'ST6', 'LB1', 'WTM3', '4210', 'BSC1', 'ST1', 'LH1', 'THTM1', '5227', 'BSC2', 'ST8', 'LB1', 'WTM2', '6226', 'BSC3', 'ST6', 'LB1', 'THTM1', '6226', 'BSC3', 'ST6', 'CR1', 'THTM2', '3225', 'BSC1', 'ST6', 'LB1', 'THTM2', '4202', 'BSC1', 'ST3', 'LH2', 'THTM1', '4222', 'BSC1', 'ST6', 'LH2', 'MTM3']
        # interchanging the genes
        for i in range(self.CROSSOVER_POINT, len(parent1)):
            parent1[i], parent2[i] = parent2[i], parent1[i]

            c1 = ''.join(parent1)
            c2 = ''.join(parent2)

        print("c1:", c1)
        print("C2:", c2)

output:

c1: 5222BSC1ST3CR1THTM25225BSC2ST6LH2MTM25225BSC2ST6LB1FTM15222BSC2ST6CR1WTM14202BSC1ST3LH1THTM24202BSC1ST3LR1MTM14227BSC1ST4LH2TTM14222BSC1ST6LB1WTM34210BSC1ST1LH1THTM15227BSC2ST8LB1WTM26226BSC3ST6LB1THTM16226BSC3ST6CR1THTM23225BSC1ST6LB1THTM24202BSC1ST3LH2THTM14222BSC1ST6LH2MTM3
C2: 4202BSC2ST6LR1FTM34222BSC1ST6LH2TTM34222BSC1ST6CR1MTM34202BSC1ST3LH2TTM26008BSC3ST1LH2FTM14210BSC1ST1LH1TTM26008BSC3ST1LH2THTM33225BSC1ST6LH2MTM24210BSC1ST1LR1THTM35225BSC2ST6LH2WTM15019BSC2ST3CR1WTM25019BSC2ST3LB1THTM14220BSC2ST5LB1MTM16008BSC3ST1LH2FTM55019BSC2ST3LH1FTM1

Although, it technically did a crossover operation, it's not what I what I'm looking for. I don't want the contents inside the sub lists to get crossover.

for example from the output above:

Children 1: 5222BSC1ST3...

would be:
[5222, 'BSC1', 'ST3']

is now different compare to it's original list in parent 1

[5222, 'BSC2', 'ST6']

Also if it's also possible to get the answer in the same format as the Expectation example


Solution

  • It seems you could use random.shuffle to shuffle pairs of sub-sublists in loop and re-assign them back to the original sublists. Since we're shuffling pairs of sub-sublists, the items inside each sub-sublist don't get shuffled.

    import random
    for lst1, lst2 in zip(parent_M, parent_F):
        for i, pair in enumerate(zip(lst1, lst2)):
            pair = list(pair)
            random.shuffle(pair)
            lst1[i], lst2[i] = pair
    

    A sample output:

    >>> parent_M
    [[[5222, 'BSC2', 'ST6'], ['CR1'], ['THTM2']],
     [[4222, 'BSC1', 'ST6'], ['LH2'], ['TTM3']],
     [[5225, 'BSC2', 'ST6'], ['LB1'], ['FTM1']],
     [[5222, 'BSC2', 'ST6'], ['LH2'], ['WTM1']],
     [[4202, 'BSC1', 'ST3'], ['LH2'], ['FTM1']],
     [[4202, 'BSC1', 'ST3'], ['LH1'], ['TTM2']],
     [[6008, 'BSC3', 'ST1'], ['LH2'], ['TTM1']],
     [[4222, 'BSC1', 'ST6'], ['LB1'], ['WTM3']],
     [[4210, 'BSC1', 'ST1'], ['LR1'], ['THTM3']],
     [[5225, 'BSC2', 'ST6'], ['LH2'], ['WTM2']],
     [[6226, 'BSC3', 'ST6'], ['CR1'], ['WTM2']],
     [[5019, 'BSC2', 'ST3'], ['CR1'], ['THTM2']],
     [[3225, 'BSC1', 'ST6'], ['LB1'], ['MTM1']],
     [[6008, 'BSC3', 'ST1'], ['LH2'], ['FTM5']],
     [[4222, 'BSC1', 'ST6'], ['LH2'], ['FTM1']]]
    
    >>> parent_F
    [[[4202, 'BSC1', 'ST3'], ['LR1'], ['FTM3']],
     [[5225, 'BSC2', 'ST6'], ['LH2'], ['MTM2']],
     [[4222, 'BSC1', 'ST6'], ['CR1'], ['MTM3']],
     [[4202, 'BSC1', 'ST3'], ['CR1'], ['TTM2']],
     [[6008, 'BSC3', 'ST1'], ['LH1'], ['THTM2']],
     [[4210, 'BSC1', 'ST1'], ['LR1'], ['MTM1']],
     [[4227, 'BSC1', 'ST4'], ['LH2'], ['THTM3']],
     [[3225, 'BSC1', 'ST6'], ['LH2'], ['MTM2']],
     [[4210, 'BSC1', 'ST1'], ['LH1'], ['THTM1']],
     [[5227, 'BSC2', 'ST8'], ['LB1'], ['WTM1']],
     [[5019, 'BSC2', 'ST3'], ['LB1'], ['THTM1']],
     [[6226, 'BSC3', 'ST6'], ['LB1'], ['THTM1']],
     [[4220, 'BSC2', 'ST5'], ['LB1'], ['THTM2']],
     [[4202, 'BSC1', 'ST3'], ['LH2'], ['THTM1']],
     [[5019, 'BSC2', 'ST3'], ['LH1'], ['MTM3']]]
    

    On a smaller sample, this produces:

    parent_M = [[[1,2], [3,4], [5]], [[6,7], [8,9,10]]]
    parent_F = [[[11,12], [13], [14,15]], [[16], [17]]]
    
    >>> parent_M
    [[[1, 2], [13], [14, 15]], [[16], [8, 9, 10]]]
    
    >>> parent_F
    [[[11, 12], [3, 4], [5]], [[6, 7], [17]]]