8.5 Definirea listelor circulare folosind comenzi inlantuite

# Definirea listelor circulare folosind comenzi inlantuite

Pe langa utilizarea constructorilor gen 'range' sau 'spread', o alta metoda de a crea noi liste circulare se bazeaza pe folosirea unora deja existente.


## Comenzi inlantuite

Pentru explorarea lor, luam ca exemplu o lista circulara simpla:

```
(ring 10, 20, 30, 40, 50)
```

Daca dorim sa obtinem o lista circulara intoarsa pe dos, putem folosi comanda '.reverse' pentru a obtine elementele in ordine inversa,:

```
(ring 10, 20, 30, 40, 50).reverse  #=> (ring 50, 40, 30, 20, 10)
```

Dar daca dorim primele trei valori din lista?

```
(ring 10, 20, 30, 40, 50).take(3)  #=> (ring 10, 20, 30)
```

In fine, ce facem daca dorim sa amestecam valorile din lista?

```
(ring 10, 20, 30, 40, 50).shuffle  #=> (ring 40, 30, 10, 50, 20)
```

## Inlantuiri multiple

Deja avem o metoda foarte buna pentru a crea noi liste circulare. Totusi, lucrurile devin cu *adevarat* interesante cand inlantuim mai multe comenzi de acest fel.

Cum facem sa amestecam lista, sa eliminam primul element si apoi sa le oprim pe primele 3?

Vom face asta in etape:

1. `(ring 10, 20, 30, 40, 50)` - lista circulara initiala
2. `(ring 10, 20, 30, 40, 50).shuffle` - o amestecam - `(ring 40, 30, 10, 50, 20)`
3. `(ring 10, 20, 30, 40, 50).shuffle.drop(1)` - eliminam 1 - `(ring 30, 10, 50, 20)`
4. `(ring 10, 20, 30, 40, 50).shuffle.drop(1).take(3)` - oprim 3 - `(ring 30, 10, 50)`

Am creat un lant cu aceste metode doar *punandu-le una dupa alta*. Putem combina aceste metode in orice ordine dorim obtinand astfel o metoda foarte puternica de a genera noi liste circulare pe baza unora deja existente.

## Invariabilitatea

Aceste liste circulare au o proprietate importanta. Ele sunt invariante, ceea ce inseamna ca nu pot fi schimbate. Metodele inlantuite descrise in aceasta sectiune *nu schimba listele* ci *creeaza noi liste*. Astfel, poti folosi acelease liste in diferite thread-uri si poti adauga comenzi inlantuite in cadrul unui thread stiind ca nu va exista un impact asupra altui thread care foloseste aceeasi lista inlantuita.

## Metode disponibile pentru transformari inlantuite

Iata o lista a metodelor disponibile pentru aceste transformari inlantuite:

* `.reverse` - intoarce o versiune a listei cu elementele in ordine inversa
* `.sort` - creeaza o versiune sortata a listei
* `.shuffle` - creeaza o versiune amestecata a listei
* `.pick(3)` - intoarce o lista cu rezultatul apelarii metodei `.choose` de 3 ori
* `.pick(3)` - intoarce o lista cu rezultatul apelarii metodei `.choose` de 3 ori
* `.take(5)` - returneaza o lista noua continand doar primele 5 elemente
* `.drop(3)` - returneaza o lista noua cu toate elementele in afara de primele 3
* `.butlast` - returneaza o lista noua fara ultimul element
* `.drop_last(3)` - returneaza o lista noua fara ultimele 3 elemente
* `.take_last(6)`- returneaza o lista doar cu ultimele 6 elemente
* `.stretch(2)` - repeta fiecare element din lista de 2 ori
* `.repeat(3)` - repeta toata lista de 3 ori
* `.mirror` - adauga la lista o versiune inversata a acesteia
* `.reflect` - la fel ca mirror, dar valoarea din mijoc nu este duplicata
* `.scale(2)` - returneaza o lista cu toate elementele inmultite cu 2 (presupune ca lista contine doar numere)

Desigur, acele metode care accepta parametri, pot primi si alte numere decat cele din exemplu! Deci poti incerca de exemplu sa apelezi .'drop(5)' in loc de '.drop(3)' daca vrei sa elimini primele 5 elemente.
