Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente | ||
site:enseignement:master:bdle:tmes:tme3-scala [11/10/2017 11:00] amine [Exercice 0] |
site:enseignement:master:bdle:tmes:tme3-scala [01/10/2018 12:39] (Version actuelle) amine |
||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
- | {{indexmenu_n>2}} | + | {{indexmenu_n>20}} |
- | ====== [TME II-1] Introduction à Scala ====== | + | ====== [Pré-requis] Introduction à Scala ====== |
- | **Remarque générale :** Le cours ne peut être //self-contained// --> consulter la documentation en ligne de Spark. | + | **Remarque générale :** Le cours ne peut être //self-contained// --> consulter la documentation en ligne de [[https://spark.apache.org/docs/2.1.1/api/scala/index.html#package|Spark]]. |
- | + | ===== Exercice 1 ===== | |
- | ===== Exercice 0 ===== | + | |
Cet exercice illustre les différentes structures de contrôle de Scala présentées en cours. Il permet de comprendre | Cet exercice illustre les différentes structures de contrôle de Scala présentées en cours. Il permet de comprendre | ||
le paradigme fonctionnel : **seules les fonctions //map, reduce, flatten, filter, flatMap// sont autorisées**. | le paradigme fonctionnel : **seules les fonctions //map, reduce, flatten, filter, flatMap// sont autorisées**. | ||
+ | |||
+ | Lancer le spark-shell en mode local ([[spark|voir Doc]]). | ||
+ | Répondre aux questions ci-dessous. | ||
==== Question 1 ==== | ==== Question 1 ==== | ||
Ligne 15: | Ligne 17: | ||
Tester au fur et à mesure ces fonctions sur listeEntiers construit comme suit : | Tester au fur et à mesure ces fonctions sur listeEntiers construit comme suit : | ||
- | Soit une liste de nombres de 1 à 100 construite à l'aide de l'instruction suivante | ||
<code scala> | <code scala> | ||
val listeEntiers = List.range(1,11) | val listeEntiers = List.range(1,11) | ||
</code> | </code> | ||
- | <showif isloggedin> | ||
**Réponse** | **Réponse** | ||
+ | <code scala> | ||
def maxEntiers(in: List[Int])= in.reduce((a,b)=>(if(a>b)a else b)) | def maxEntiers(in: List[Int])= in.reduce((a,b)=>(if(a>b)a else b)) | ||
def scEntiers(in: List[Int])= in.map(e=>e*e).reduce((a,b)=>(a+b)) | def scEntiers(in: List[Int])= in.map(e=>e*e).reduce((a,b)=>(a+b)) | ||
def moyEntiers(in: List[Int])={val p = in.map(e=>(1,e)).reduce((a,b)=>(a._1+b._1, a._2+b._2)); p._2/p._1} | def moyEntiers(in: List[Int])={val p = in.map(e=>(1,e)).reduce((a,b)=>(a._1+b._1, a._2+b._2)); p._2/p._1} | ||
- | </showif> | + | </code> |
==== Question 2 ==== | ==== Question 2 ==== | ||
Ligne 32: | Ligne 33: | ||
val listeTemp = List("7,2010,04,27,75", "12,2009,01,31,78", "41,2009,03,25,95", "2,2008,04,28,76", "7,2010,02,32,91") | val listeTemp = List("7,2010,04,27,75", "12,2009,01,31,78", "41,2009,03,25,95", "2,2008,04,28,76", "7,2010,02,32,91") | ||
</code> | </code> | ||
- | Chaque élément représente un enregistrement fictif de températures avec le format (station, année, mois, température, code_département) | + | Chaque élément représente un enregistrement fictif de températures avec le format (station, année, mois, température, code_département). |
- | * Calculer pour chaque année le maximum de ses température. | + | * Calculer pour l'année 2009 le maximum de ses températures. |
- | * Calculer pour chaque année la moyenne de ses température. | + | * Idem pour la moyenne de ces température. |
+ | |||
+ | Bien entendu, il faudra faire les transformations et les conversions de type nécessaires! | ||
- | <showif isloggedin> | ||
**Réponse** | **Réponse** | ||
- | </showif> | + | <code scala> |
+ | val temp2009 = listeTemp.map(x=>x.split(",")).filter(_(1).toInt==2009).map(x=>x(3).toInt) | ||
+ | maxEntiers(temp2009) | ||
+ | moyEntiers(temp2009) | ||
+ | </code> | ||
Ligne 45: | Ligne 51: | ||
Soit une liste chaine de caractères construite à l'aide de l'instruction suivante | Soit une liste chaine de caractères construite à l'aide de l'instruction suivante | ||
<code scala> | <code scala> | ||
- | val melange = List("u123,f01,3,20171010", "u24,f02,4,20171009", "f01,lala,comedie", "f02,loup,documentaire") | + | val melange = List("1233,100,3,20171010", "1224,22,4,20171009", "100,lala,comedie", "22,loup,documentaire") |
</code> | </code> | ||
Deux types d'éléments existent : ceux de la forme (userID, movieID, rating, timestamp) et ceux de la forme | Deux types d'éléments existent : ceux de la forme (userID, movieID, rating, timestamp) et ceux de la forme | ||
(movieID, title, genre). | (movieID, title, genre). | ||
+ | Le domaine des userID est [1000, 2000] et celui des movieID est [0, 100]. | ||
Il est demandé de construire à partir de //melange// deux listes distinctes : | Il est demandé de construire à partir de //melange// deux listes distinctes : | ||
- | * //notes// contenant les éléments de la forme (userID, movieID, rating, timestamp) et dont le type est (String, String, Int, Int) ; | + | * //notes// contenant les éléments de la forme (userID, movieID, rating, timestamp) et dont le type est (Int, String, Int, Int) ; |
- | * //films// contenant les éléments de la forme (movieID, title, genre) et dont le type est (String, String, String). | + | * //films// contenant les éléments de la forme (movieID, title, genre) et dont le type est (Int, String, String). |
- | <showif isloggedin> | ||
**Réponse** | **Réponse** | ||
- | </showif> | + | <code scala> |
+ | val notes = melange.map(_.split(",")).filter(_(0).toInt>=1000).map(x=>(x(0).toInt,x(1), x(2).toInt, x(3).toInt)) | ||
+ | val films = melange.map(_.split(",")).filter(_(0).toInt<=100).map(x=>(x(0).toInt,x(1), x(2))) | ||
+ | </code> | ||
==== Question 4 ==== | ==== Question 4 ==== | ||
Ligne 82: | Ligne 90: | ||
- | <showif isloggedin> | ||
**Réponse** | **Réponse** | ||
<code scala> | <code scala> | ||
Ligne 90: | Ligne 97: | ||
val classes_personnes = personnes.map(x=> x match { case(a,"ens",b) =>new Ens(a,b); case(a, "etu", b) =>new Etu(a,b); case _=>None}).filter(_!=None) | val classes_personnes = personnes.map(x=> x match { case(a,"ens",b) =>new Ens(a,b); case(a, "etu", b) =>new Etu(a,b); case _=>None}).filter(_!=None) | ||
</code> | </code> | ||
- | </showif> | ||
- | ===== Exercice 1 : Spark ===== | + | ===== Exercice 2 ===== |
Commencer par copier et décompresser dans votre espace de travail le fichier | Commencer par copier et décompresser dans votre espace de travail le fichier | ||
Ligne 128: | Ligne 134: | ||
+ | **Réponse** | ||
+ | <code scala> | ||
+ | //1. Extraire dans une variable appelée listEnt le 4e champ de chaque élément de data. | ||
+ | val q1 = data.map(x=>x.split(" ")).map(x=>x(3).toDouble) | ||
- | ===== Exercice subsidiaire ===== | + | //2. Construire à partir de q1 une liste contenant les nombres compris strictement entre 1000 et 1300 puis convertir en type entier. |
- | ==== Conversion d'un objet List en un objet Map ==== | + | val q2 = q1.filter(x=> x>1000 && x<1300 )map(x=>x.toInt) |
- | Expliquer l'expression | + | |
- | <code scala> | + | |
- | val x = List(("ALice",22), ("Bob",20), ("Charles",22)).toMap | + | |
- | val x = List((22, "ALice"), (20, "Bob"), (22, "Charles")).toMap | ||
- | </code> | + | //. Construire à partir de q2 une liste contenant les multiples de 3 et l’appeler q33. Faire |
+ | val q33 = q2.filter(x=>x%3==0) | ||
+ | val q39 = q2.filter(x=>x%9==0) | ||
- | ==== Illustration du flatMap ==== | + | //4. Construire une liste obtenue en divisant par 10 chaque élément de q33. |
- | Expliquer la différence entre les expressions map et flatMap suivantes : | + | val q4 = q33.map(x=>x/10) |
- | <code scala> | + | //5. Construire à partir de q4 un ensemble d’éléments (liste sans doublons). |
- | val x = List(1, 2, 3).map(x => List(x, 10*x, 100*x) | + | |
- | val x = List(1, 2, 3).flatMap(x => List(x, 10*x, 100*x)) | + | |
- | val y = List(List((1, 11), (1, 111)), List((2, 22), (2, 222))).map(x => x) | + | val q5 = q4.distinct |
- | val y = List(List((1, 11), (1, 111)), List((2, 22), (2, 222))).flatMap(x => x) | + | |
- | </code> | ||
- | <code scala> | + | //6. Construire à partir de q2 une liste contenant ses qui sont multiples de 3 et de 9 à la fois. Utiliser impérativement q33 et q39. |
- | val ys = Map("a" -> List(1 -> 11, 1 -> 111), "b" -> List(2 -> 222, 2 -> 22)).flatMap(_._1) | + | |
- | </code> | + | |
- | Attention, le flatMap appliqué sur une Map retourne une Map. Pour garantir l'unicité de la clé seules la dernière occurence d'une paire (k,v) est conservée. | + | val q6 = q33.intersection(q39) |
- | <code scala> | + | |
- | val ys = Map("a" -> List(1 -> 11, 1 -> 111), "b" -> List(2 -> 222, 2 -> 22)).flatMap(_._2) | + | |
- | </code> | + | |
- | La fonction passée en paramêtre au flatMap doit retourner une séquence. Ici une chaine de caractère est considérée implicitment comme une séquence de caractères. | ||
- | <code scala> | ||
- | val pers = Array( (1,"pierre"), (5,"alice"), (4, "paul")) | ||
- | val v = pers.flatMap(x=>x._2) | ||
- | val v = pers.flatMap{ case(numéro, prénom) =>prénom) | ||
+ | //7. Construire à partir de q2 une liste contenant ses éléments qui sont multiples de 3 mais pas de 9. Utiliser impérativement q33 et q39. | ||
+ | |||
+ | val q7 = q33.subtract(q39) | ||
+ | |||
+ | //8. Construire à partir de q2 une liste contenant ses éléments qui sont multiples de 3 ou de 10. | ||
+ | |||
+ | val q8 = q33.union(q2.filter(x=>x%3==0)) | ||
+ | |||
+ | //9. Calculer la somme, la moyenne, le minium ainsi que le maximum des éléments de q8. | ||
+ | |||
+ | val q9sum = q8.map(x=>x.toDouble).reduce(_+_) | ||
+ | |||
+ | val q9max = q8.map(x=>x.toDouble).reduce((x,y)=>if (x > y) x else y) | ||
+ | |||
+ | val q9min = q8.map(x=>x.toDouble).reduce((x,y)=>if (x < y) x else y) | ||
+ | |||
+ | val q9avg = q8.map(x=>(x,1)).reduce((x,y)=>(x._1+y._1,x._2+y._2)) | ||
+ | |||
+ | q9avg._1/q9avg._2 | ||
</code> | </code> | ||
- | ==== Composition de Map ==== | ||
- | En considérant la variable pers de la question précédente, expliquer le résultat des instructions suivantes | ||
- | * pers.flatMap(x=>(x._2) map(y=>y)) | ||
- | * pers.flatMap(x=>(x._2) map(y=>x._1)) | ||
- | * pers.flatMap(x=>(x._2) map(y=>x._2)) | ||
- | et expliquer pourquoi les deux instructions suivantes sont erronées | ||
- | * pers.flatMap(x=>(x._1) map(y=>y)) | ||
- | * pers.flatMap(x=>(x._2) map(y=>y._1))) |