Programmation Javascript (NFA041)

Feuille 4

Olivier Pons
(pons@cnam.fr)

2022

Tableaux et fonctions en argument

On a vu l'exemple de la fonction map en cours qui construit un nouveau tableau en appliquant une fonction f passée en argument à chaque élément du tableau.

Sans utiliser les méthodes équivalente de Array écrire les fonctions suivante:

Exercice 1

Écrire une fonction forEach(t,f) qui execute la fonction f sur le tableau t (ie. en séquence sur chaque element de t). Elle ne renvoie rien, seul les effets de bord nous intéressent

Exemple:

> forEach( ["Pif", "Hercule", "Placid","Muzo"],
            (x)=>console.log("Salut "+x))
Salut Pif
Salut Hercule
Salut Placid
Salut Muzo
undefined
> 

Solution

function forEach(t,f){
    for( let i in t)
      f(t[i])
}

Exercice 2

Écrire une fonction exists (t,f) ou f est une fonction booléenne ou prédicat (ie qui renvoie true ou false )

Telle que exists([a1 , ... , an],f) vérifie si au moins un élément de la liste satisfait le prédicat f (elle renvoie alors true, sinon elle renvoie false)

>  exists([1, 2, 3],( x => x% 2 === 0)) ;

`true

Solution


function exists(t,f){
    let i=t.length;
    while(i>0){
        i--;
        if(f(t[i])===true)
            {return true}
    }
    return false;
}

ou version recursive

function exists(t,f){
    let [p,...r]=t
    if (p===undefined) {return false}
    else{return  f(p)||exists(r,f)}      
}

Exercice 3

Écrire une fonction filter (t,f) qui renvoie tous les éléments du tableau t qui satisfont le prédicat f. L'ordre des éléments du tableau d'entrée est préservé.

> filter ( [1,2, 3, 4, 5],(x=>x%2===0))
[ 2, 4 ]
>

Solution

function filter(t,f){
    let res=[];
    for(let i=0;i<t.length;i++){
        if(f(t[i])){res.push(t[i])}
    }
    return res
}

ou version récursive

function filter(t,f){
  let find =(t,accu)=>{
    let [p,...r]=t
    if(t.length<1){return accu}
    else {return f(p)?find(r,(accu.push(p),accu)):find(r,accu)
    }
  }
  return find(t,[])
  }

Exercice 4

Écrire une fonction map2(f,t1,t2) qui se comporte comme map mais qui prend 2 tableaux en argument et une fonction à 2 arguments.
map2(f,[a1, ..., an],[b1, ..., bn]) renvoie [f(a1,b1), ...,f(an,bn)].

> map2 ( (x,y)=>x+y , [1, 2, 3],[4, 5, 6])
[ 5, 7, 9 ]

On pourra lever une exception si les tableaux n'on pas la meme taille. On peut aussi choisir de renvoyer false

Solution

function map2(f,t1,t2){
    if(t1.length != t2.length){
        throw new Error("les tableaux doivent être de meme taille" )
    }
    let res=[];
    for(let i=0;i<t1.length;i++){
        res.push(f(t1[i],t2[i]))
    }
    return res;
}

Exercice 5

Écrire une fonction exists2(f,t1,t2), identique à exists, mais pour un prédicat f à deux arguments et donc deux tableaux en argument.

On pourra lever une exception si les tableaux n'on pas la meme taille. On peut aussi choisir de renvoyer false

>  exists2 ((x,y)=>(y%x===0),[2, 4, 8],[11, 12, 13])
true
>  exists2 ((x,y)=>(y%x===0),[2, 4, 8],[11, 13, 115])
false
> 

Solution

function exists2(f,t1,t2){
    if(t1.length != t2.length){
        throw new Error ( "les tableaux doivent être de meme taille" )
    }
    let i=t1.length;
    while(i>0){
        i--;
        if(f(t1[i],t2[i])===true)
            {return true}
    }
    return false;
}

Exercice 6

Écrire une fonction partition(t,f) telle que partition(t,f) renvoie un objet {ok:t1, ko:t2), où t1 est le tableau de tous les éléments de t qui satisfont le prédicat f, et t2 est la liste de tous les éléments de t qui ne satisfont pas f. L'ordre des éléments dans la liste d'entrée est préservé.

> partition ([1, 2, 3, 4, 5], (x)=> x % 2 === 0) 
{ ok: [ 2, 4 ], ko: [ 1, 3, 5 ] }
> 

Solution

function  partition(t,f){
  function part (t,yes, no){
    let [p,...r]=t;
    if (t.length<1){return {ok:yes,ko:no}}
   else{

  return  f(p)?part(r,(yes.push(p),yes), no): part(r,yes, (no.push(p),no)) 
  }
  }

  return part (t,[], [])
}

Chaines et tableaux

Exercice 7

Écrire une fonction qui compte le nombre de mot d'un texte.
On considérera que les mots sont toujours séparés par des espaces.

> compteMots("Tout a l'air si compliqué")
5
> 

Solution

function compteMots(s){
    return s.split(" ").length;
}

Exercice 8

Écrire une fonction qui compte le nombre de phrase d'un texte. On considérera que les phrases toujours séparées par des points suivies d'un espace.

let texte=`
 Tout a l'air si compliqué. Tout est si simple pourtant.
Si j'avais eu la lune, si l'amour suffisait, tout serait changé.`
> comptePhrases(texte)
3
> 

Solution

function comptePhrases(s){
    return s.split(". ").length;
    }

Exercice 9

Écrire deux fonctions sommeet produit prenant en argument un chaîne caractère contenant uniquement des nombres et renvoyant respectivement leur somme et leur produit.

> somme("1 2 8 6")
17
> produit("1 2 8 6")
96
> 

Solution

function somme(s){
    let res=0;
    s.split(" ").forEach(x=>res+=0+Number(x)); // conversion obligatoire !!!
    return res;
}

//comme précédemment avec * ,ou plus classique
function produit(s){
    let res=1;
    let t= s.split(" ");
    for(let i=0;i<t.length;i++){
        res*=Number(t[i]) // le Number pourrait être omis
    }                      // avec * conversion vers number
    return res
}

ou avec la méthode reduce

function produit(s){
return s.split(" ").reduce(
  (accumulateur, valeurCourante) => accumulateur * valeurCourante,
  1
);
}

Exercice 10

Écrire une fonction qui prend un caractère français et si c'est une voyelles accentuée ou le ç renvoie la version sans accent ou sans cédille; sinon elle renvoie le caractère inchangé

> sansDiacritique("é")
'e'
> sansDiacritique("à")
'a' 
> sansDiacritique("u")
'u'

Solution

en utilisant juste indexOf c'est pas du tout optimal ...

function sansDiacritique(l){
    if ("àâä".indexOf(l)!=-1){return "a"} 
    if("éèêë".indexOf(l)!=-1){return "e"} 
    if("îï".indexOf(l)!=-1){return "i"} 
    if("ôö".indexOf(l)!=-1){return "o"} 
    if("ùûü".indexOf(l)!=-1){return "u"} 
    if(l==="ÿ"){return "y"} 
    if(l==="ç"){return "c"} 
    return l
}

Exercice 11

Écrire une fonction qui prend une chaîne de caractère français et renvoie une version sans accent et sans cédille.

Solution

function sansDiacritiqueChaine(s){
    res="";
    for(let i=0;i<s.length;i++){
        res+=sansDiacritique(s[i])
    }
    return res
}

En utilisant split , map et join

function sansDiacritiqueChaine(s){
    return s.split("").map(sansDiacritique).join("")

}

Ou optimal et plus générale, mais moins compréhensible sans rentrer dans les acharnes des encodages ... voir stackoverflow

let s="après l'été à dubaï"

> s.normalize("NFD").replace(/[\u0300-\u036f]/g, "")
"apres l'ete a dubai"
> 

Exercice 12

Écrire une fonction qui trie les mots d'un texte par ordre alphabétique. On considérera que les mots sont sans accents (on pourra s'y ramener avec la question précédente) et toujours séparés par des espaces .

On renverra un tableau triés (avec éventuellement des doublons), et mettant tout les mots en minuscule.

let texteSansAccent=`Tout a l'air si complique. Tout est si simple 
pourtant. Si j'avais eu la lune, si l'amour suffisait, tout serait 
change.`

> triMots(texteSansAccent)
[
  'a',          'change.',
  'complique.', 'est',
  'eu',         "j'avais",
  "l'air",      "l'amour",
  'la',         'lune,',
  'pourtant.',  'serait',
  'si',         'si',
  'si',         'si',
  'simple',     'suffisait,',
  'tout',       'tout',
  'tout'
]

Solution


function triMots(s){
    return s.toLowerCase().split(" ").sort()
}

Pour avoir quelque chose d'un peu plus propre

il faut utiliser une Expression_régulière dans split

function triMots(s){
    return s.toLowerCase().split(/[ ';,!?]/).sort()
}

Exercice 13

Deux chaîne de caractère sont des anagrammes s' ils ont même longueurs sont composés des même lettres, mais dans des ordres potentiellement différents.

Écrire une fonction qui teste si deux chaines sont des anagrammes.

On pourra utiliser les méthodes split , sort et join vues dans les corrections précédentes

> EstAnagramme("romain","manoir")
true
> EstAnagramme("sortie","toiser")
true
> EstAnagramme("posture","poste")
false
> 

Solution

function EstAnagramme (str1, str2) {
    //si les longueurs
    //sont différente ce n'est pas des anagram 
    if (str1.length !== str2.length) {
        return false;
    }
    
    //sinon on tri les caractères des deux chaînes.
    var s1 = str1.split('').sort().join('');
    var s2 = str2.split('').sort().join('');
    //on compare les deux chaînes triées.
    return (s1 === s2);
}

Sur les matrices

Exercice 14

Les matrices peuvent être vues comme des tableaux à deux dimensions. On a vu dans la feuille d'exercice précédente une fonction pour créer un tableau de longueur n rempli 0. On veut ici une fonction pour créer une matrice n x m rempli de 0

> creerMatrice(3,4)
[ [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ] ]
> 

Solution

function creerMatrice(n,m){
    let mat=[];
    for(let i=0;i<n;i++){
        let colj=[]
        for(let j=0;j<m;j++){
            colj[j]=0
    }
    mat[i]=colj;
}
return mat;
}

Exercice 15

Ecrire une fonction qui créer une matrice n x m initialisée avec des nombre aléatoires entre 0 et n*m.

On rappel que la fonction Math.random permet de générer un nombre aléatoire entre 0 et 1 (exclu). Et que Math.floor permet d'obtenir la partie entière.

> creerMatrice(3,5)
[ [ 3, 7, 12, 9, 6 ], [ 6, 14, 14, 3, 14 ], [ 5, 13, 0, 0, 7 ] ]
> creerMatrice(3,5)
[ [ 10, 3, 13, 14, 0 ], [ 12, 6, 11, 6, 7 ], [ 0, 11, 13, 15, 4 ] ]
> creerMatrice(3,5)
[ [ 14, 9, 1, 12, 8 ], [ 13, 2, 3, 11, 6 ], [ 3, 4, 1, 3, 12 ] ]
> 

Solution


function RandomInt(n){return Math.floor(Math.random()*(n+1)) }

function creerMatrice(n,m){
    let max=n*m;
    let mat=[];
    for(let i=0;i<n;i++){
        let colj=[]
        for(let j=0;j<m;j++){
            colj[j]=RandomInt(max)
    }
    mat[i]=colj;
}
return mat;
}

Revision, implémenter un algo

Exercice 16

## multiplication russe

On peut calculer le produit \(n_1 \times n_2\) de la façon suivante :

Le procédé s’arrête lorsque \(n_1\) tombe à zéro.

Écrire une fonction multRusse implémentant cette idée.

Solution



function multRusse(a, b) {
    let res = 0;
    while (a > 0) {
        if (0 === (a % 2)) { //pair
             a = a / 2;
             b = 2 * b;
        }
        else {               //impair
            res = res + b;
            a--;
        }
    }
    return res;

}


// ou si on copie le pseudo code de wikipedia
function multRusse2(a, b) {
    let res = 0;
    while (a > 0) {

        
        if (0 === (a % 2)) { //pair
            
        }
        else {               //impair
            res = res + b;
            a--;
        }

        a = a / 2;
        b = 2 * b;
    }
    return res;

}