# -*- coding: utf-8 -*-
"""
TP4 : Listes

PCSI2 - Albert Schweitzer - Le Raincy
"""

##Q3
def maximum(L:list) -> int:
    '''
    Renvoie l'indice de la première apparition
    du maximum dans L
    '''
    max = 0 #position du max
    for i in range(len(L)):
        if L[i] > L[max]:
            max = i
    return max

##Q4
L = list(range(101))
L[:42]
L[len(L) - 42:]
L[:21] + L[len(L) - 21:]
L[::2]
##Q5
import random as rd

L = [rd.random() for i in range(1000)]
from math import log, pi
M = [x for x in L if (x < log(2) and x > 1/pi)]

##Q6
def carres(n:int) -> list:
    '''
    Renvoie une liste contenant les carrés des
    n premiers entiers naturels
    '''
    return [i**2 for i in range(n)]

##Q7
def non_div3(n:int) -> list:
    '''
    Renvoie la liste des entiers de [[0, n-1]]
    qui ne sont pas divisibles par 3
    '''
    return [i for i in range(n) if i%3 != 0]

##Q8
def ajouteUn(L:list) -> None:
    '''
    Ajoute 1 à tous les éléments de L
    '''
    for i in range(len(L)):
        L[i] = L[i] + 1

##Q9
def moyenne(L:list) -> float:
    '''
    Renvoie la moyenne des éléments de L
    '''
    s = 0
    for element in L:
        s = s + element
    return s/len(L)

##Q10
import matplotlib.pyplot as plt
from math import e
def u(n):
    '''
    Param : n, int
    Ret : list
    Renvoie la liste des n premiers termes de la suite
    '''
    L = [1]
    for i in range(n-1):#on a déjà le premier terme
        L.append(L[-1]*(1+1/e**(i+1)))#u_i est L[-1]
    return L

N = list(range(100))
U = u(100)
plt.plot(N, U, 'x')
plt.show()

##Q11
import matplotlib.pyplot as plt
from math import exp

for n in [5, 20, 200, 2000]:
    X = [2*i/(n-1) for i in range(n)]
    Y = [exp(x) for x in X]
    plt.plot(X,Y)
plt.show()

##Q12
def est_croissante(L:list) -> bool:
    '''
    Renvoie True si L est croissante
    '''
    for i in range(len(L) - 1):
        if L[i] > L[i+1]:#La liste n'est pas croissante !
            return False #On s'arrête
    return True #Tout va bien

##Q13
def evalPoly(L:list, x:float) -> float:
    '''
    Evalue en x le polynôme dont les coefficients
    sont dans L
    '''
    p = 0
    for i in range(len(L)):
        p = L[i] * x**i
    return p
##Q14
def renverse(L:list) -> None:
    '''
    Modifie la liste L en la renversant
    '''
    for i in range(len(L)//2):
        L[i], L[-i-1] = L[-i-1], L[i]

##Q15
def pop2(L:list):
    '''
    Supprime l'avant dernier élément de L
    et le renvoie
    '''
    dernier = L.pop()
    adernier = L.pop()
    L.append(dernier)
    return adernier

##Q16
scrabble={"A":1,"B":3,"C":3,"D":2,"E":1,"F":4,"G":2,"H":4,"I":1,"J":8,"K":10,"L":1,"M":2,"N":1,"O"
:1,"P":3,"Q":8,"R":1,"S":1,"T":1,"U":1,"V":4,"W":10,"X":10,"Y":10,"Z":10}
def points(mot:str) -> int:
    '''
    Renvoie le nombre de points de mots
    au scrabble
    '''
    p = 0
    for lettre in mot:
        p = p + scrabble[lettre]
    return p

##Q17
def note(reponses_prof:dict, reponses_eleve:dict) -> int:
    '''
    Renvoie la note de l'élève au QCM
    '''
    n = 0
    for question in reponses_eleve:
        if reponses_eleve[question] == reponses_prof[question]:
            n = n + 3
        else:
            n = n - 1
    return n

##Q18
def occ(chaine:str) -> dict:
    '''
    Renvoie le nombre d'occurences de A, T, G, C
    dans chaine
    '''
    d = {'A':0, 'T':0, 'G':0, 'C':0}
    for lettre in chaine:
        d[lettre] = d[lettre] + 1
    return d

def plus_souvent(chaine:str) -> str:
    '''
    Renvoie la lettre qui apparaît le plus souvent
    dans chaine
    '''
    d = occ(chaine)
    max = 0
    for lettre in d:
        if d[lettre] > max:
            max = d[lettre]
            l = lettre
    return l

##Q19
def compte(L:list) -> dict:
    '''
    L est une liste d'entiers entre 0 et 99
    Renvoie le dictionnaire (entier, occurencedansL)
    '''
    d = {i:0 for i in range(100)}
    for entier in L:
        d[entier] = d[entier] + 1
    return d

def trie(L:list) -> list:
    '''
    L est une liste d'entier entre 0 et 99
    Renvoie une copie triée de L
    '''
    d = compte(L)
    M = []
    for i in range(100):
        for j in range(d[i]):
            M.append(i)
    return M

##Q20
def fusion(L:list, M:list) -> list:
    '''
    Prend deux listes triées et les fusionne
    '''
    F = []
    i1 = 0
    i2 = 0
    while i1 < len(L) and i2 < len(M):
        if L[i1] < M[i2]:
            F.append(L[i1])
            i1 = i1 + 1
        else:
            F.append(M[i2])
            i2 = i2 + 1
    while i1 < len(L):
        F.append(L[i1])
        i1 = i1 + 1
    while i2 < len(M):
        F.append(M[i2])
        i2 = i2 + 1
    return F
##Q21
import random as rd

def melange(L:list) -> None:
    '''
    Mélange la liste L
    '''
    for i in range(len(L)):
        j = rd.randint(0, i)
        L[i], L[j] = L[j], L[i]