Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
pp:2023:hw2_v2 [2023/04/10 10:42]
pdmatei
pp:2023:hw2_v2 [2023/04/11 00:04] (current)
sorin.mateescu [2. Functii de procesare a datelor (50p)]
Line 3: Line 3:
 <note important>​ <note important>​
  
-**DEADLINE ​TODO **+**DEADLINE ​28 aprilie 2023**
  
   * Temele trebuie submise pe curs.upb.ro,​ in assignment-ul numit ''​Tema 2''​.   * Temele trebuie submise pe curs.upb.ro,​ in assignment-ul numit ''​Tema 2''​.
Line 15: Line 15:
   * **var** (**val** este ok!)   * **var** (**val** este ok!)
 </​note>​ </​note>​
-<​note>​Scheletul se poate găsi la: TODO</​note>​+<​note>​Scheletul se poate găsi la: {{:​pp:​2023:​tema2_2023_pp-skel.zip|}}</​note>​
 <​note>​ <​note>​
-Validatorul de arhive se poate găsi la: TODO+Validatorul de arhive se poate găsi la: {{:​pp:​2023:​archive_validator_hw2.zip|}}
 \\ \\
 Formatul arhivelor este: Formatul arhivelor este:
-  * TODO+  * util/​Util.scala 
 +  * Table.scala 
 +  * TestTables.scala
   * ID.txt - acest fisier va contine o singura linie, formata din ID-ul unic al fiecarui student   * ID.txt - acest fisier va contine o singura linie, formata din ID-ul unic al fiecarui student
 Numele arhivelor trebuie sa fie de forma **<​Nume>​_<​Prenume>​_<​Grupa>​_T2.zip** (daca aveti mai multe prenume sau nume, le puteti separa prin '​-'​) Numele arhivelor trebuie sa fie de forma **<​Nume>​_<​Prenume>​_<​Grupa>​_T2.zip** (daca aveti mai multe prenume sau nume, le puteti separa prin '​-'​)
Line 43: Line 45:
  
  
-==== Conventii ​==== +==== Tabele ​==== 
-Pentru reprezentarea tabelelor din Query Languagese vor folosi ​urmatoarele conventii+ 
-  * numele coloanelor ​este reprezentat sub forma de lista +Un tabel este in esenta o matrice ce contine elemente de tip ''​String''​alaturi de cate un **nume** asociat fiecarei coloane, necesar pentru a descrie cu usurinta operatii peste acestea. In aceasta tema, vom folosi ​doua reprezentari pentru o linie a unei matrici, fiecare potrivita in contexte diferite
-  * fiecare linie a tabelului e reprezentata ca o mapare intre numele colanei si valoarea ​corespunzatoare+  * ''​Line''​ - este pur si simplu o lista cu valorile liniei corespunzatoare. 
 +  * ''​Row''​ - este un Map in care asociaza numelui coloanei ​valoarea ​de pe linia respectiva. 
 <code scala> <code scala>
 // a row contains the column name and the value // a row contains the column name and the value
Line 52: Line 56:
 // a line is just a row without column names // a line is just a row without column names
 type Line = List[String] type Line = List[String]
- 
 </​code>​ </​code>​
  
-====1. ​Parsarea ​datelor==== +====1. ​Tipul de date Table si parsarea ​datelor ​(10p) ==== 
-Pentru inceput, trebuie sa ne definim o clasa prin care sa modelam ce este un tabel.+ 
 +Pentru inceput, trebuie sa definim o clasa prin care sa modelam ce este un tabel.
  
-Vom implementa clasa ''​Table'' ​ce retine numele coloanelor si informatia din tabel.+Vom implementa clasa ''​Table'' ​in acest sens:
 <code scala> <code scala>
-case class Table (column_names:​ Line, tabular: List[List[String]]) { +class Table (column_names:​ Line, tabular: List[List[String]]) { 
     ???     ???
 } }
Line 67: Line 71:
 Pentru a putea rula checkerul, este nevoie sa putem parsa input si output. Prin urmare, avem nevoie de o functie de citire si una de afisare a unui tabel. Pentru a putea rula checkerul, este nevoie sa putem parsa input si output. Prin urmare, avem nevoie de o functie de citire si una de afisare a unui tabel.
  
-**1.1.** Suprascrieti metoda ''​toString''​ a unui tabel, astfel incat sa puteti reprezenta un tabel in forma csv.+**1.1. ​(5p)** Suprascrieti metoda ''​toString''​ a unui tabel, astfel incat sa puteti reprezenta un tabel in forma csv.
 Liniile vor fi separate prin ''​\n'',​ iar coloanele vor fi delimitate prin '',''​. Liniile vor fi separate prin ''​\n'',​ iar coloanele vor fi delimitate prin '',''​.
  
-**1.2.** Definiti functia ''​apply''​ intr-un companion object al clasei ''​Table''​. Functia trebuie sa parseze un sir de caractere si sa returneze un tabel, daca acest lucru este posibil.+**1.2. ​(5p)** Definiti functia ''​apply''​ intr-un companion object al clasei ''​Table''​. Functia trebuie sa parseze un sir de caractere si sa returneze un tabel.
 <code scala> <code scala>
 def apply(s: String): Table = ??? def apply(s: String): Table = ???
 </​code>​ </​code>​
  
-====2. Functii de procesare a datelor====+====2. Functii de procesare a datelor ​(50p)====
  
-In continuare, vom implementa operatii pe tabele.+In continuare, vom implementa operatii pe tabele, ca **membri** ai clasei ''​Table''​.
  
-**2.1.** Implementati functia ''​select''​ care selecteaza valorile din tabel asociate unor coloane date ca input. Daca operatia ​nu este posibila/​permisase va marca aces lucru folosind ​''​None''​.+**2.1. ​(5p)** Implementati functia ''​select''​ care selecteaza valorile din tabel asociate unor coloane date ca input. Daca operatia ​face referire la coloane inexistenteea va intoarce ​''​None''​.
 <code scala> <code scala>
 def select(columns:​ Line): Option[Table] = ??? def select(columns:​ Line): Option[Table] = ???
 </​code>​ </​code>​
  
-**2.2.** Implementati functia ''​filter''​ care aplica un filtru pe liniile din tabel, fiind pastrate doar acele linii care verifica conditia.+**2.2. ​(20p)** Implementati functia ''​filter''​ care aplica un filtru pe liniile din tabel, fiind pastrate doar acele linii care verifica conditia. Daca conditia de filtrare face referiri la coloane inexistente,​ operatia va intoarce ''​None''​.
 <code scala> <code scala>
 def filter(cond:​ FilterCond):​ Option[Table] = ??? def filter(cond:​ FilterCond):​ Option[Table] = ???
 </​code>​ </​code>​
  
-Pentru acest exercitiu, este nevoie sa implementam si filtrele ce se aplica pe o linie din tabel. ​Astfelexista+Pentru acest exercitiu, este nevoie sa implementam si filtrele ce se aplica pe o linie din tabel. ​Definim un filtru recursivastfel
-  * filtre logice --aplica functiile logice AND si OR intre 2 filtre +<code>  
-  * filtre asociate unei coloane --decid pastrarea/eliminarea unei linii pe baza unui predicat ce primeste numele unei coloane+<filter::= <​filter>​ && <​filter>​ | <​filter>​ || <​filter>​ | (<​column_name>​ <​predicate>​) 
 +</code> 
 + 
 +Unde ''<​column_name>''​ este un nume de coloana, iar <​predicate>​ este un predicat ce poate sau nu sa fie satisfacut de valoarea de la coloana respectiva. 
 <code scala> <code scala>
 trait FilterCond { trait FilterCond {
-  def &&​(other:​ FilterCond):​ FilterCond = And(this,​other) +  ​// these are useful for the intuitive infix notation 
-  def ||(other: FilterCond):​ FilterCond = Or(this,​other)+  // e.g. the following expression is a filter condition:​ 
 +  // Field("​PL",​ x=>true) && Field("​PL",​ x=> false) 
 +  ​def &&​(other:​ FilterCond):​ FilterCond = ??? 
 +  def ||(other: FilterCond):​ FilterCond = ??? 
 +  ​
   // fails if the column name is not present in the row   // fails if the column name is not present in the row
   def eval(r: Row): Option[Boolean]   def eval(r: Row): Option[Boolean]
 +  ​
 } }
  
Line 113: Line 126:
 </​code>​ </​code>​
  
-**2.3** Implementati functia ''​newCol''​ ce adauga o noua coloana la finalul unui tabel, fiecare intrare in acea coloana asociata unei linii fiind completata cu o valoare default.+**2.3. (5p)** Implementati functia ''​newCol''​ ce adauga o noua coloana la finalul unui tabel, fiecare intrare in acea coloana asociata unei linii fiind completata cu o valoare default.
 <code scala> <code scala>
 def newCol(name:​ String, defaultVal: String): Table = ??? def newCol(name:​ String, defaultVal: String): Table = ???
 </​code>​ </​code>​
  
-**2.4.** Implementati functia ''​merge''​ care uneste 2 tabele. Identificarea liniilor ce trebuie combinate se va face folosing coloana comuna ''​key''​. Daca exista suprapuneri intre valori, se vor pastra amandoua sub forma unui singur sir de caractere (cele doua intrari vor fi separate prin '';''​),​ iar acolo unde nu exista corespondent in unul dintre tabele, coloanele ramase necompletate vor fi umplute cu un sir de caractere gol. Daca coloana ''​key''​ nu exista in vreunul din tabele, se va intoarce None.+**2.4. ​(20p)** Implementati functia ''​merge''​ care uneste 2 tabele. Identificarea liniilor ce trebuie combinate se va face folosing coloana comuna ''​key''​. Daca exista suprapuneri intre valorile asociate unei chei in cele doua tabele, se vor pastra amandoua ​valorile (daca sunt diferite) ​sub forma unui singur sir de caractere (cele doua intrari vor fi separate prin '';''​),​ iar acolo unde nu exista corespondent in unul dintre tabele, coloanele ramase necompletate vor fi umplute cu un sir de caractere gol. Daca coloana ''​key''​ nu exista in vreunul din tabele, se va intoarce ​''​None''​.
 <code scala> <code scala>
 def merge(key: String, other: Table): Option[Table] = ??? def merge(key: String, other: Table): Option[Table] = ???
 </​code>​ </​code>​
 +
 <hidden Exemplu> <hidden Exemplu>
 <​code>​ <​code>​
Line 136: Line 150:
  
 MERGE intre TABEL 1 si TABEL 2 cu cheia PL: MERGE intre TABEL 1 si TABEL 2 cu cheia PL:
-PL      Functional OO   Description +PL      Functional ​Description ​OO 
-Haskell yes        "" ​  nice +Haskell yes        ​nice ​       ""​ 
-Scala   ​yes ​       yes  cool +Scala   ​yes ​       ​cool ​       yes 
-Python ​ yes        ​yes  ​good;whoa+Python ​ yes        good;​whoa ​  yes
 </​code>​ </​code>​
 </​hidden>​ </​hidden>​
  
-====3. Query Language ====+====3. Query Language ​(40p)====
  
 Obiectivul acestui task este acela de a: Obiectivul acestui task este acela de a:
Line 151: Line 165:
     * debug, testare     * debug, testare
  
-Veti implementa un Query Language ce reprezinta un API pentru o varietate de transformari de tabele, deja implementate anerior ca functii. Un ''​Query''​ este o secventa/ combinatie de astfel de transformari.+**3.0. (25p)** ​Veti implementa un Query Language ce reprezinta un API pentru o varietate de transformari de tabele, deja implementate anerior ca functii. Un ''​Query''​ este o secventa/ combinatie de astfel de transformari. 
 + 
 +Query-urile sunt descrise recursiv astfel: 
 +<​code>​ 
 +<​query>​ ::=  <​table> ​                              // query atomic - reprezinta tabelul initial pe care se va realiza query-ul. ​   
 +             | Select <​column_list>​ <​query> ​       //​selecteaza o lista de coloane dintr-un tabel dat, 
 +                                                   //​esueaza daca se doreste o coloana ce nu se gaseste in tabel 
 +             | NewCol <​column_name>​ <​query> ​       //creeaza o noua coloana cu nume dat intr-un tabel, completand coloana cu o valoare default 
 +                                                   //​operatia e posibila doar daca cheia se gaseste in ambele tabele 
 +             | Merge <​column_name>​ <​query>​ <​query>​ //combina 2 tabele pe baza unei chei comune 
 +                                                   //​operatia e posibila doar daca cheia se gaseste in ambele tabele 
 +             | Filter <​filter_cond>​ <​query> ​       //aplica un filtru pe liniile tabelei 
 + 
 +</​code>​
  
-Query-uri posibile: +Spre exemplu, pentru a evalua query-ul: ''​Select "​PL"​ <Q>''​, se va evalua intai query-ul ​''​<Q>'' ​apoi se va efectua operatia //Select// pe rezultatul intors ​de ''​Q''​. 
-  * ''​Value''​ +Scheletul de implementare pentru Query-uri se gaseste ​mai jos:
-    * reprezentarea de baza a unui tabel sub forma de Query +
-  * ''​Select''​ +
-    * selecteaza o lista de coloane dintr-un tabel dat +
-    * esueaza daca se doreste o coloana ce nu se gaseste in tabel +
-  * ''​NewCol''​ +
-    * creeaza o noua coloana cu nume dat intr-un tabel, completand coloana cu o valoare default +
-  * ''​Merge''​ +
-    * combina 2 tabele pe baza unei chei comune +
-    * operatia e posibila doar daca cheia se gaseste ​in ambele tabele +
-  * ''​FIlter''​ +
-    * aplica un filtru pe liniile tabelei+
  
 <code scala> <code scala>
Line 195: Line 211:
 In finalul acestei teme, vom scrie propriul nostru Query, folosind tabelele Functional, Object-Oriented si Imperative, ce contin doar 3 coloane: "​Language",​ "​Original purpose",​ "Other paradigms"​. In finalul acestei teme, vom scrie propriul nostru Query, folosind tabelele Functional, Object-Oriented si Imperative, ce contin doar 3 coloane: "​Language",​ "​Original purpose",​ "Other paradigms"​.
  
-**3.1.** Creati tabelul ''​TestTables.programmingLanguages1''​ combinand functiile ''​newCol''​ si ''​merge'':​+**3.1. ​(5p)** Creati tabelul ''​TestTables.programmingLanguages1''​ combinand functiile ''​newCol''​ si ''​merge'':​
   * creati o noua colana in fiecare tabel ce contine tipul limbajului, avand acelasi nume ca tabela si valoare default "​Yes"​   * creati o noua colana in fiecare tabel ce contine tipul limbajului, avand acelasi nume ca tabela si valoare default "​Yes"​
   * aplicati merge intre noile tabele dupa numele limbajelor de programare   * aplicati merge intre noile tabele dupa numele limbajelor de programare
  
-**3.2** Eliminati limbajele al caror scop original este "​Application"​ si sunt "​concurrent"​. Rezultatul se va numi ''​TestTables.programmingLanguages2''​.+**3.2. (5p)** Eliminati limbajele al caror scop original este "​Application"​ si sunt "​concurrent"​. Rezultatul se va numi ''​TestTables.programmingLanguages2''​.
  
-**3.3** Selectati doar coloanele "​Language",​ "​Object-Oriented" ​and "​Functional"​ din tabelul obtinut anterior. Rezultatul se va numi ''​TestTables.programmingLanguages3''​.+**3.3. (5p)** Selectati doar coloanele "​Language",​ "​Object-Oriented" ​si "​Functional"​ din tabelul obtinut anterior. Rezultatul se va numi ''​TestTables.programmingLanguages3''​.