def filter_ctrl_pert(gse_gsm_info):
    """
    Filter the GSE that do not contain both control and perturbation samples
    Args:
        gse_gsm_info: the GSE and GSM info tuple

    Returns:
        True if there are both control and perturbation samples, False otherwise
    """
    gse_id, gsm_info = gse_gsm_info
    sample_types = gsm_info[3]
    has_ctrl = has_pert = False

    for sample_type in sample_types:
        if has_ctrl and has_pert:
            break

        if sample_type == "ctrl":
            has_ctrl = True
        elif sample_type == "pert":
            has_pert = True

    return has_ctrl and has_pert