Salta ai contenuti. | Salta alla navigazione

Strumenti personali

15 giugno 2017 - laboratorio

Linguaggi e Traduttori

Prof. Marco Gavanelli

15 giugno 2017

Esercizio 1 (punti 20)

Una potente funzionalità dei programmi SpreadSheet moderni è quella delle pivot table. L'utente ha la possibilità di selezionare un insieme di dati, in cui ogni riga rappresenta un record con vari campi, rappresentati nelle colonne.

Ad esempio, un commerciante ambulante vende ortaggi in vari mercati della regione; ha creato la seguente tabella, che indica le vendite dei vari ortaggi nei mercati della regione:

Ortaggio luogo giorno vendite
carote Ravenna venerdi` 100
patate Ravenna giovedi` 50
carote Bologna lunedi` 20
patate Bologna martedi` 30
patate Ferrara mercoledi` 10
patate Ferrara giovedi` 20
carote Ravenna martedi` 10
patate Ferrara lunedi` 20
carote Ferrara lunedi` 20
Table 1: Esempio di dati in ingresso nello spreadsheet

L'ambulante desidera sapere, per ogni coppia (Ortaggio, Luogo) quanto è stato venduto, ovvero desidera creare una tabella come segue (detta, appunto, Pivot Table):

Bologna Ferrara Ravenna
carote 20 20 110
patate 30 50 50
Table 2: Tabella Pivot corrispondente alla tabella 1

Per creare una pivot table, l'utente seleziona:

  • i dati da mettere in riga nella pivot table: DatiRiga (nell'esempio, la colonna "Ortaggio")
  • i dati da inserire in colonna nella pivot table: DatiColonna (nell'esempio, la colonna "Luogo")
  • i dati da inserire nelle celle della pivot table: DatiCelle (nell'esempio, la colonna "vendite").

L'utente seleziona poi come aggregare i dati che vanno nella stessa cella della pivot table (nell'esempio, l'ambulante vuole sapere la somma delle vendite fatte di un dato ortaggio in un certo luogo, per cui selezionerà la funzione somma come aggregazione).

screenshotPivot.png

Il software di spreadsheet a questo punto crea una tabella in cui

  • è presente una riga per ogni valore presente nella colonna DatiRiga (nell'esempio, la colonna selezionata è "ortaggio" e in tale colonna sono presenti due possibili valori: "patate" e "carote")
  • è presente una colonna per ogni valore presente nella colonna DatiColonna (nell'esempio, la colonna selezionata era la colonna "luogo", per cui i valori possibili sono "Ravenna", "Ferrara" e "Bologna").
  • per ogni coppia (DatoRiga,DatoColonna) (dove DatoRiga è un valore presente in DatiRiga e DatoColonna è uno dei valori presenti in DatiColonna) è presente una cella che contiene l'aggregazione di tutti i dati della tabella di dati originari (Nell'esempio, la tabella 1),

Per comprendere meglio l'esempio, si può utilizzare il file EsempioPivot.ods , aprirlo con uno spreadsheet, selezionare tutti i dati, poi

  • insert → pivot Table
  • poi trascinare nel riquadro Row Fields il campo Ortaggio,
  • poi trascinare nel riquadro Column Fields il campo luogo,
  • poi trascinare nel riquadro Data Fields il campo vendite,
  • infine cliccare ok e viene creata la Pivot Table.

Si crei una funzione Haskell pivot che crea una pivot table rappresentata come lista di liste (da intendersi come matrice). La funzione prende come parametri:

  • una lista l
  • tre funzioni, che servono a selezionare, della lista l
    • il dato da mettere in riga
    • il dato da mettere in colonna
    • il dato da inserire nelle celle
  • la funzione di aggregazione
  • (A scelta dello studente): l'elemento neutro della funzione di aggregazione (se la funzione di aggregazione è la somma, si può inserire 0 in questo argomento).

L'interfaccia sarà dunque:

pivot :: [a] -> (a -> a1) -> (a -> a2) -> (a -> a3) -> (a3 -> b -> b) -> b -> [[b]]

Ad esempio, se i dati nella tabella 1 sono rappresentati in Haskell con il tipo

data Ambulante = Ambulante {ortaggio::String, luogo::String, giorno::String, vendite::Int}

ed inseriti in una lista chiamata lista, ad es:

let lista = [(Ambulante "carote" "Ravenna" "venerdi`" 100),(Ambulante "patate" "Ravenna" "giovedi`" 50),...]}

allora l'ambulante potrà invocare

pivot lista ortaggio luogo vendite (+) 0

ed ottenere:

[[20,20,110],[30,50,50]]

Se invece si volesse il prodotto come funzione di aggregazione:

Prelude> pivot lista ortaggio luogo vendite (*) 1
[[20,20,1000],[30,4000,50]]

 

 


Soluzione

pivot l sx sy sz agg null =
let valx = remdup (map sx l)
valy = remdup (map sy l)
in map (create_row l sx sy sz valy agg null) valx

create_row l sx sy sz ys agg null vx =
map (create_item l sx sy sz agg null vx) ys

create_item ls sx sy sz agg null vx vy =
let list = [ sz k | k <- ls, (sx k) == vx, (sy k) == vy]
in foldr agg null list

-- rimozione duplicati con quicksort
remdup [] = []
remdup (x:xs) =
(remdup [y| y<-xs, y<x]) ++ (x:(remdup [y| y<-xs, y>x]))