Redis permette di creare liste in grado di salvare sequenze di valori, collegandole ad una chiave. Tali strutture dati possono essere utilizzate mediante funzioni che permettono inserimento di valori (in testa, in coda o in una posizione specifica), lettura di informazioni e cancellazioni. La varietà delle funzioni disponibili permette di usare le liste come:
- array: gli elementi sono accessibili in base alla loro posizione;
- code: si segue una politica FIFO (First In First Out) secondo la quale il primo elemento inserito sarà il primo estratto. Ciò viene attuato con inserimenti in coda ed estrazioni dalla testa;
- pila: implementa una logica LIFO (Last In First Out), vale a dire che l'ultimo elemento
inserito sarà il primo estratto. Si realizza il tutto con inserimenti ed estrazioni dallo stesso lato della lista.
Esaminiamo ora nel dettaglio le funzioni disponibili, suddivise per tipologie di azione.
Inserimento di elementi
Per inizializzare una lista, è sufficiente specificare la chiave cui essa corrisponde, ed inserirvi elementi. Con la funzione LPUSH possiamo inserire uno o più elementi in testa alla lista:
> LPUSH animali topo
(integer) 1
> LPUSH animali gatto cane
(integer) 3
Con queste due operazioni abbiamo prima inserito la stringa "topo" nella lista "animali", e successivamente le stringhe "gatto" e "cane". Gli elementi a questo punto sono tre e la composizione attuale della struttura dati è la seguente:
[cane, gatto, topo]
Inserendo più elementi in testa, LPUSH
porrà in prima posizione sempre l'ultimo elemento aggiunto. Con la funzione RPUSH possiamo analogamente richiedere inserimenti in coda:
> RPUSH animali asino cavallo
(integer) 5
La lista verrà trasformata in questo modo:
[cane, gatto, topo, asino, cavallo]
Si noti che dopo ogni inserimento Redis notifica la nuova dimensione della lista. Questa informazione può comunque essere richiesta in qualsiasi momento con la funzione LLEN:
> LLEN animali
(integer) 5
Esistono altre due funzioni per l'inserimento in testa e in coda, LPUSHX e RPUSHX, dal funzionamento analogo a quelle appena viste ma utilizzabili solo se la lista già esiste.
Accesso ai dati
L'accesso agli elementi di una lista può essere svolto con:
- LINDEX: accesso ad un singolo elemento in base alla posizione;
- LRANGE: accesso ad un gruppo di elementi sequenziali inclusi in un range di cui indichiamo la posizione iniziale e quella finale.
Vediamo qualche esempio partendo dalla lista costruita nel paragrafo precedente.
La funzione LINDEX
richiede solo l'indicazione della chiave di accesso alla lista e la posizione dell'elemento.
Si noti che le posizioni vengono conteggiate a partire da 0, perciò il primo elemento verrà identificato dalla posizione 0:
> LINDEX animali 0
"cane"
Se invece la posizione passata non esiste, viene restituito il valore nil
:
> LINDEX animali 10
(nil)
Sono considerati validi anche indici negativi: il loro effetto sarà il reperimento di un elemento a partire dalla coda della lista, conteggiando da -1. Ad esempio, l'elemento in posizione -2 è il penultimo della lista:
> LINDEX animali -2
"asino"
Con la funzione LRANGE
si può ottenere un elenco di elementi specificando, oltre alla chiave, due indici:
> LRANGE animali 0 2
1) "cane"
2) "gatto"
3) "topo"
La numerazione riportata in corrispondenza di ogni elemento è puramente progressiva e non coincide con le posizioni degli elementi nella lista. Si noti comunque che sono stati riportati tre elementi in quanto entrambi gli indici rappresentano dei limiti inclusivi.
Inserimento di elementi
Nuovi elementi possono essere inseriti nella lista anche in posizioni interne, quindi nè in testa nè in coda. Per svolgere tali operazioni, possiamo utilizzare due funzioni:
- LSET, inserisce un elemento in una data posizione sostituendo il valore precedente. Si può fornire un indice positivo (ed in questo caso il conteggio partirà da 0 dalla testa) o uno negativo (ed in questo caso
il conteggio partità da -1 dalla coda). Non è possibile fornire un indice inesistente nella lista; - LINSERT, possiamo richiedere di inserire un nuovo elemento prima o dopo di un altro già presente.
Anche in questo caso passiamo ad alcuni esempi pratici. Partiamo dalla solita lista di animali (["cane", "gatto", "topo", "asino", "cavallo"]).
Inseriamo due nuovi elementi: "coniglio" in posizione 1 e "gallo" in posizione -1:
> LSET animali 1 coniglio
OK
> LSET animali -1 gallo
OK
> LLEN animali
(integer) 5
> LSET animali 11 tacchino
(error) ERR index out of range
Al termine delle operazioni, gli elementi della lista sono ancora 5 in quanto la funzione LSET
ha provveduto a sostituire il secondo (indice 1) e l'ultimo (indice -1). Quando infine si è fornito un indice non valido (11), è stato generato un messaggio di errore. La composizione finale della lista è pertanto ["cane", "coniglio", "topo", "asino", "gallo"].
Con la funzione LINSERT
è sufficiente specificare l'elemento vicino al quale vogliamo collocarne uno nuovo. Con le parole BEFORE
e AFTER
indicheremo l'ordine secondo il quale avverrà l'inserimento. Le seguenti istruzioni collocano la stringa "tacchino" prima (BEFORE
) di "topo", e la stringa "pecora" dopo (AFTER
) "gallo". Il terzo esempio restituisce -1 a simboleggiare un fallimento dell'operazione di inserimento, in quanto la stringa "cammello" non fa parte della lista.
> LINSERT animali BEFORE topo tacchino
(integer) 6
> LINSERT animali AFTER gallo pecora
(integer) 7
> LINSERT animali AFTER cammello giraffa
(integer) -1
Dopo questi passaggi, gli elementi della lista saranno sette: ["cane", "coniglio", "tacchino", "topo", "asino", "gallo", "pecora"].
Rimozione ed estrazione
Con la funzione LREM, è possibile eliminare un determinato numero di istanze di un elemento nella lista. Con il comando seguente eliminiamo un'istanza di "gallo":
> LREM animali 1 gallo
(integer) 1
Il numero che viene restituito indica quanti elementi sono stati davvero eliminati. Se si richiede l'eliminazione
di un elemento inesistente, il risultato che si ottiene è 0.
Le funzioni LPOP e RPOP sono il corrispondente di LPUSH
e RPUSH
: estraggono un elemento dalla testa o
dalla coda. La loro utilità consiste nel poter usare la struttura dati come coda o pila, implementando le politiche FIFO o LIFO di cui si è detto. Con queste funzioni, un valore verrà rimosso dalla lista ma sarà contemporaneamente eliminato. Gli esempi che seguono estraggono sequenzialmente i primi due elementi dalla testa della lista ed un altro dalla coda. Quando si stampa il contenuto della struttura dati, si trovano solo tre elementi al suo interno, dimostrazione che LPOP
e RPOP
fanno coincidere una rimozione con ogni estrazione.
> LPOP animali
"cane"
> LPOP animali
"coniglio"
> RPOP animali
"pecora"
> LRANGE animali 0 10
1) "tacchino"
2) "topo"
3) "asino"