# Corrigé / Épreuve pratique NSI 2026, sujet 2
# Solutions identiques à celles publiées dans la correction.

import donnees
import donnees_completes
from math import sqrt


def salaire_moyen_condition(employes, champ, valeur):
    '''Renvoie le salaire moyen des employes ayant val comme valeur associée
    au champ donné en argument.
    Si le nombre d'employés considéré est nul, cette fonction renvoie None'''
    total = 0  # la somme des salaires retenus
    nombre = 0  # le nombre d'employés retenus
    for employe in employes:
        if employe[champ] == valeur:  # champ sans guillemets : c'est le paramètre
            total = total + employe['salaire']  # on ajoute son salaire...
            nombre = nombre + 1  # ... et on le compte
    if nombre == 0:  # personne ne correspond
        return None
    return total / nombre  # '/' renvoie toujours un float


# Forme compacte présentée dans l'article (non active) :
#
# def salaire_moyen_condition(employes, champ, valeur):
#     salaires = [e['salaire'] for e in employes if e[champ] == valeur]
#     if len(salaires) == 0:
#         return None
#     return sum(salaires) / len(salaires)


def test_salaire_moyen_condition():
    e = donnees.employes
    assert salaire_moyen_condition([], 'sexe', 'F') == None
    assert salaire_moyen_condition(e, 'sexe', 'F') == 2400.0
    assert salaire_moyen_condition(e, 'etudes', 3) == 2550.0
    assert salaire_moyen_condition(e, 'etudes', 12) == None


def effectif_par_sexe(employes):
    '''Renvoie un dictionnaire ayant deux clés 'F' et 'M'
    associée respectivement au nombre d'employées femmes et au
    nombre d'employés hommes dans les données en arguments.'''
    effectif = {'F': 0, 'M': 0}  # les deux clés existent dès le départ
    for employe in employes:
        if employe['sexe'] == 'F':
            effectif['F'] = effectif['F'] + 1  # une femme de plus
        else:
            effectif['M'] = effectif['M'] + 1  # un homme de plus
    return effectif  # aligné avec le for, pas dedans


def test_effectif_par_sexe():
    e = donnees.employes
    assert effectif_par_sexe(e) == {'F': 3, 'M': 3}


def calcul_ecart_sexe(employes):
    '''Renvoie l'écart de salaire en pourcentage pour les femmes 
    par rapport aux hommes'''
    moy_h = salaire_moyen_condition(employes, 'sexe', 'M')
    moy_f = salaire_moyen_condition(employes, 'sexe', 'F')  # plus de guillemets
    if moy_h == None or moy_f == None:  # un seul sexe présent...
        return None  # ... pas d'écart possible
    return (moy_h - moy_f) / moy_h * 100  # la formule de l'énoncé


def test_calcul_ecart_sexe():
    e = donnees.employes
    que_des_femmes = [e[0], e[2], e[4]]  # les lignes F du jeu de test
    que_des_hommes = [e[1], e[3], e[5]]  # les lignes M du jeu de test
    assert calcul_ecart_sexe(que_des_femmes) == None
    assert calcul_ecart_sexe(que_des_hommes) == None
    assert calcul_ecart_sexe([]) == None  # aucun des deux sexes
    ecart = calcul_ecart_sexe(e)
    assert 0 <= ecart <= 100  # un pourcentage, pas des euros

# Attribution d'un premier salaire après embauche par les k plus proches voisins


def sexe_vers_entier(e):
    if e['sexe'] == 'F':
        return 1
    else:
        return -1


def distance(e1, e2):
    '''Renvoie la mesure de distance entre deux personnes.'''
    s = 0
    s = s + (e1['experience'] - e2['experience'])**2  # l'expérience
    s = s + (e1['etudes'] - e2['etudes'])**2  # les études, et plus rien d'autre
    return sqrt(s)


def k_plus_proches(k, employes, e):
    '''Renvoie les k employes les plus proches de e par la 
    distance définie au dessus.'''
    e_d = [(distance(e, employes[i]), i) for i in range(len(employes))]
    e_d.sort()  # va trier en premier sur la distance
    voisins = []
    for i in range(k):
        voisins.append(employes[e_d[i][1]])
    return voisins


def salaire_moyen(employes):
    '''Renvoie le salaire moyen pour une liste d'employes'''
    if len(employes) == 0:
        return None
    s = sum(e['salaire'] for e in employes)
    return s/len(employes)


def salaire_par_proximite(employes, e):
    '''Prend en entrée une liste d'employés et un dictionnaire comportant
    les champs experience, etudes et sexe et renvoie le salaire le plus
    proche en moyennant les 3 plus proches voisins'''
    voisins = k_plus_proches(3, employes, e)
    return salaire_moyen(voisins)


# ------------------------------------------------------------ Question 1

test_salaire_moyen_condition()

complet = donnees_completes.employes
print("Femmes :", round(salaire_moyen_condition(complet, 'sexe', 'F'), 2))
print("Hommes :", round(salaire_moyen_condition(complet, 'sexe', 'M'), 2))

# ------------------------------------------------------------ Question 2

test_effectif_par_sexe()
print(effectif_par_sexe(donnees.employes))
print(effectif_par_sexe(donnees_completes.employes))

# ------------------------------------------------------------ Question 3

test_salaire_moyen_condition()
test_calcul_ecart_sexe()
print(round(calcul_ecart_sexe(donnees.employes), 2))
print(round(calcul_ecart_sexe(donnees_completes.employes), 2))

# ------------------------------------------------------------ Question 4

candidate = {'experience': 3, 'etudes': 3, 'sexe': 'F'}
candidat = {'experience': 3, 'etudes': 3, 'sexe': 'M'}

assert salaire_par_proximite(donnees.employes, candidate) == salaire_par_proximite(donnees.employes, candidat)
print(round(salaire_par_proximite(donnees.employes, candidate), 2))
print(round(salaire_par_proximite(donnees.employes, candidat), 2))
