Lavorare con le liste: quando il gioco si fà duro… (parte 2)

6 08 2009

google_translate.gif Translate To English!

Avete “digerito” la prima parte? Ok, allora proseguiamo! Nella prima parte abbiamo parlato anche degli array, gestendoli però con alcuni semplici metodi standard. newLisp però prevede delle funzioni (di cui alcune già viste la volta scorsa) per la manipolazione di liste-array. Prima di tutto, facciamo un “brutale” copia/incolla dal manuale, e vediamo quali funzioni abbiamo a nostra disposizione:

append Appende gli array
array Crea ed inizializza un array fino a 16 dimensioni
array-list Converte un array in una lista
array? Controlla se una espressione è un array
det Ritorna il determinante di una matrice
first Ritorna la prima riga di un array
invert Ritorna l’inversa di una matrice
last Ritorna l’ultima riga di un array
mat Esegue operazioni scalari su matrici
multiply Moltiplica due matrici
nth Ritorna un elemento di un array
rest Ritorna tutti gli elementi di un array tranne il primo
setf Set (imposta) i contenuti di un array per reference
slice Ritorna uno slice (una parte, un sottoinsieme) di un array
sort Mette in ordine gli elementi di un array
transpose Traspone una matrice

Alcune note importanti:

  1. Gli array multidimensionali vengono gestiti come array di array.
  2. Quando usato in modo interattivo, gli array sono mostrati come liste, e non c’è nessun modo per distinguerli.
  3. Gli array possono essere non-rettangolari, ma quando vengono serializzati diventano rettangolari.
  4. La funzione array crea sempre array rettangolari.
La nota più importante di tutte: gli array così creati sono veri array, e non liste! Questo significa che non si possono applicare su di essi tutte le funzioni che normalmente si applicano sulle liste, e che gli array possono fornire “out-of-bounds error” (cosa che non può accadere con le liste).

E allora quando dobbiamo usare gli array? Vanno usati quando si devono gestire GRANDI quantità di dati, ad accesso casuale, i quali risultano troppo lenti per essere gestiti tramite le liste. Per inizializzare un array dobbiamo procedere in questo modo:

> (array 2 3)
((nil nil nil) (nil nil nil))

Se volessimo inserire un elemento all’interno durante la sua creazione, aggiungiamolo con una lista:

> (array 2 3 '(1))
((1 1 1) (1 1 1))
> (array 2 3 (sequence 1 6))
((1 2 3) (4 5 6))
> (array 2 3 '("X"))
(("X" "X" "X") ("X" "X" "X"))

Per inserire un valore nell’array possiamo ricorrere alla funzione setf, che inserirà il valore “by-reference” (quindi è molto veloce):

> (setq mio (array 2 3 '(".")))
(("." "." ".") ("." "." "."))
> (setf (mio 0 1) "X")
"X"
> mio
(("." "X" ".") ("." "." "."))
> (setf (mio 1 2) "Z")
"Z"
> mio
(("." "X" ".") ("." "." "Z"))
Ricordatevi che gli indici partono sempre da zero!

Possiamo anche lavorare con array in altri array:

> (setf (mio 1 0) '(A B C))
(A B C)
> mio
(("." "X" ".") ((A B C) "." "Z"))
> (setf (mio 1 ) '(X Y Z))
(X Y Z)
> mio
(("." "X" ".") (X Y Z))

Nell’ultimo caso ho sostituito un intera dimensione dell’array (in termini di contenuti) con un’altra! Ed ora guardate qui:

> (setf (mio 3 ) '(W A S D))
ERR: array index out of bounds in function setf : 3

Ho cercato di inserire un elemento in un posto inesistente, ed ho ottenuto un Out of bounds. Questo perchè la funzione (setf), lavorando per reference, deve necessariamente lavorare su elementi esistenti (non si può referenziare qualcosa che non esiste!).

Come posso estrarre i dati di una riga? Ed una cella singola? Guardate questi esempi:

> (setq mio (array 4 3 (sequence 0 11)))
((0 1 2) (3 4 5) (6 7 8 ) (9 10 11))
> (mio 1 1)
4
> (mio 1)
(3 4 5)

> (mio -1) ;; INDICE NEGATIVO: LEGGO L'ULTIMO ELEMENTO!
(9 10 11)

Si possono anche estrarre “pezzi” di array, tramite la funzione (slice):

> (slice mio 1 2)
((3 4 5) (6 7 8))

Per essere certi di lavorare con degli array, possiamo usare la funzione (array?):

> (setq mio (array 3 2 (sequence 1 6)))
((1 2) (3 4) (5 6))
> (array? mio)
true
> (array? (array-list mio)) ;; CONVERTO L'ARRAY IN LISTA
nil

> (list? (array-list mio)) ;; CONVERTO L'ARRAY IN LISTA
true

Invece se si vuole convertire una lista in un array, dobbiamo usare la funzione (flat) che si occuperà di “appiattire” la lista e darla in pasto al generatore di array:

> (setq mioArray (array 2 3 (flat lista)))
((1 2 3) (4 5 6))
> (setq mioArray (array 3 2 (flat lista)))
((1 2) (3 4) (5 6))

E’ interessante notare come questo sistema permetta di “distribuire” i valori nell’array, senza preoccuparsi della “forma” dell’array stesso nè della forma della lista.

Prima di concludere (ma la terza parte di questo workshop è già alle porte ;-)  ) vediamo le funzioni (source) (save). Esse permettono di serializzare espressioni, simboli, context, etc… e, ovviamente, array!

Facciamo subito una prova:

> (setq mioArray (array 3 2 (sequence 1 6)))
((1 2) (3 4) (5 6))

> (println (source 'mioArray))
(set 'mioArray (array 3 2 (flat '(
  (1 2)
  (3 4)
  (5 6)))))

"(set 'mioArray (array 3 2 (flat '(\n  (1 2) \n  (3 4) \n  (5 6)))))\n\n"

Ho aggiunto la funzione (println) per comodità di lettura. La funzione (source) genera tutto l’indispensabile per ricrare l’elemento da un’altra parte, o per salvarlo. La funzione (source) fà la stessa cosa, ma salva il codice generato direttamente su file.

Ora pensate al potenziale di queste funzioni, unite alla (net-eval).

Come dite? Non sapete cosa è la (net-eval)?! Ne parleremo in un prossimo workshop, insieme alla programmazione distribuita. Promesso!


Azioni

Informazione

2 risposte

8 08 2009
Darkini

we sempre ottime le tue guide peccato che nn ti fai piu sentire su msn se ti ricordo di me scorpion.2 ciao grx di tutto

16 08 2009
sguish

Ciao,

è molto tempo che non vado su msn, perchè sono impegnato in ben tre progetti (mi rimane quindi pochissimo tempo libero). Magari un pò più in là ci sentiremo di nuovo!
NOTA: grazie per i complimenti, mi fà piacere sapere che non hai smesso di usare newLisp :-)
A presto!

Lascia un commento