Compute Blood Types

Doing another painful irrelevant code question about inheritance and blood types and came up with this

Given

/**
* @param parent1 The phenotype of the first parent (A, B, AB or O)
* @param parent2 The phenotype of the second parent (A, B, AB or O)
* @param child The phenotype of the child (A, B, AB or O)
* @return A list of list of string, containing all the possible blood genes of the two parents.
*/

This means that if you have for instance, A and B are dominant and O is only recessive therefore

  • Parent1: AB
  • Parent2: A
  • Child: A

The results are AB, AA or AB, AO as in the second parent could have an O gene or be a duplicate AA . That is because the child produced is A which is the way you check the parent possible outputs. As in the above there is no way for an O child to be produced.

C#

public static List<List<string>> ComputeBloodGenes(string parent1, string parent2, string child)
{
	var combos = (from p1 in NormalizeParent(parent1)
		from p2 in NormalizeParent(parent2)
		select new List<string> { p1, p2 }).ToList();

	var validPairs = (from combo in combos
		let firstParent = combo.First()
		let secondParent = combo.Last()
		let result1 = $"{firstParent[0]}{secondParent[0]}"
		let result2 = $"{firstParent[0]}{secondParent[1]}"
		let result3 = $"{firstParent[1]}{secondParent[1]}"
		let result4 = $"{firstParent[1]}{secondParent[0]}"
		where GetPhenoType(result1) == child ||
			  GetPhenoType(result2) == child ||
			  GetPhenoType(result3) == child ||
			  GetPhenoType(result4) == child
		select combo).ToList();

	if (validPairs.Count == 0)
	{
		validPairs.Add(["--", "--"]);
	}

	return validPairs;
	
	List<string> NormalizeParent(string parent)
	{
		if (parent.Length != 1)
		{
			return [parent];
		}

		return parent switch
		{
			"A" => ["AA", "AO"],
			"B" => ["BB", "BO"],
			"O" => ["OO"],
			_ => [parent]
		};
	}
	
	string GetPhenoType(string input)
	{
		return input switch
		{
			"AA" or "AO" or "OA" => "A",
			"BB" or "BO" or "OB" => "B",
			"OO" => "O",
			_ => "AB"
		};
	}			

}

Python

from icecream import ic

def possible_parent_genes(phenotype: str) -> list[str]:
    match phenotype:
        case "A":
            return ["AA", "AO"]
        case "B":
            return ["BB", "BO"]
        case "AB":
            return ["AB"]
        case "O":
            return ["OO"]
        case _:
            return []

def get_phenotype(input_gene: str) -> str:

    match input_gene:
        case input_gene if input_gene in ["AA", "AO", "OA"]:
            return "A"
        case input_gene if input_gene in ["BB", "BO", "OB"]:
            return "B"
        case input_gene if input_gene in ["AB", "BA"]:
            return "AB"
        case "OO":
            return "O"
        case _:
            return ""

def compute_blood_lines(parent1: str, parent2: str, child: str) -> list[list[str]]:
    combos = [
        [p1, p2]
        for p1 in possible_parent_genes(parent1)
        for p2 in possible_parent_genes(parent2)
    ]

    valid_pairs = [
        combo
        for combo in combos
        if any(
            get_phenotype(result) == child
            for result in [
                combo[0][0] + combo[1][0],
                combo[0][0] + combo[1][1],
                combo[0][1] + combo[1][1],
                combo[0][1] + combo[1][0],
            ]
        )
    ]

    if not valid_pairs:
        valid_pairs.append(["--", "--"])

    return valid_pairs

if __name__ == "__main__":
    ic(compute_blood_lines('AB', 'A', 'A'))
    ic(compute_blood_lines('AB', 'A', 'O'))
    ic(compute_blood_lines('A', 'O', 'O'))
ic| compute_blood_lines('AB', 'A', 'A'): [['AB', 'AA'], ['AB', 'AO']]
ic| compute_blood_lines('AB', 'A', 'O'): [['--', '--']]
ic| compute_blood_lines('A', 'O', 'O'): [['AO', 'OO']]