Colectii
In toate limbajelor OOP (si functionale) exista multe structuri de date care sa ajute programatorul pentru diverse aplicatii, un grup foarte important de structuri de date utilitare sunt colectiile. O colectie este o clasa generica care sa organizaze mai multe obiecte intr-un anumit mod si sa ofere operatii de acces si modificare pe acestea. Utilitatea colectiilor este data de speializarea acestora, anume cat de multa memorie si cat timp se consuma pentru diferite operatii.
Cele mai uzuale colectii sunt liste, seturi si dictionare/mapuri:
- List<T> - cel mai des folosit tip de lista din C#, implementarea din spate fiind de array list. Are performante bune pentru acces indexat in O(1) dar inserarile si stergerile sunt in cazul cel mai defavorabil e O(n).
- LinkedList<T> - implementeaza o lista dublu inlantuita avand performante mai slabe ca List<T>. Accesul indexat este in O(n) dar inserarea si stergerea la capatele listei este de O(1).
- HashSet<T> - este un set neordonat care are performante ridicate in care nu pot exista elemente dublicate. Se foloseste metoda GetHashCode() si Equals() a tipului T ca sa se determine unde sa fie pus un element in structura interna care e o tabela de dispersie. Asta inseamna ca T trebuie sa aiba suprascrise aceste metode. Are in cazul mediu perfomenate aproape de O(1) la toate tipurile de operatii dar devine O(n) daca contine foarte multe elemente.
- SortedSet<T> - este un set ordonat care are performante bune constante deoarece pastreaza ordinea elementelor si nu admite duplicate. Elementele de tip T trebuie sa implementeze IComparable<T> sau sa i se dea in constructorul colectiei un IComparator<T> pentru a gasi ordinea elementelor. Intern mentine un arbore ros-negru. Operatiile de acces si modificare peste acest set sunt de O(log n) mereu.
- Dictionary<TKey, TValue> - este un map/tabel neordonat cu chei de tip TKey pentru a accesa valori de tip TValue. Mentine intern o tabela de dispersie ca HashSet si se comporta la fel ca acesta doar ca se foloseste de GetHashCode() si Equals() din TKey.
- SortedDictionary<TKey, TValue> - este un map/tabel ordonat cu chei de tip TKey pentru a accesa valori de tip TValue. Mentine intern arbore ros-negru ca SortedSet si se comporta la fel ca acesta doar ca se foloseste de un IComparator<TKey> sau de TKey care implementeaza IComparable<TKey>.
- SortedList<TKey, TValue> - functioneaza similar ca SortedDictionary<TKey, TValue> doar ca structura interna este o lista sortata, din acest motiv desi accesul este O(log n) inserarile si stergerile sunt de O(n) dar este mai rapid pentru a accesa indexat valorile listei.
Alte colectii folositoare sunt:
- Stack<T> - implementeaza o coada de tip LIFO.
- Queue<T> - implementeaza o coada de tip FIFO.
- PriorityQueue<TElement, TPriority> - implementeaza o coada de prioritati pentru elemente de tip TElement si ordonate dupa valori de tip TPriority dand un IComparator<TPriority> sau avand TPriority care implementeaza IComparable<TPriority>.
Dupa cum se vede, trebuie sa aveti atentie ce alegeti ca structura de date pentru programele voastre pentru ca o sa impacteze performanta dar si logica programulului folosirea unei colectii sau alteia. Cel mai probabil o sa folositi in majoritatea cazurilor clasele List<T> si Dictionary<TKey, TValue> dar e bine sa stiti si despre celelalte structuri de date in cazurile in care aveti nevoie.
Resurse
📄️ Enumeratii
Pe langa colectii, in C# exista si conceptul de enumeratie (enumerable) care incapsuleaza conceptul de structura de date iterabila, adica o enumeratie poate fi parcursa iterativ. Toate colectiile implementeaza interfata IEnumerable<T> si sunt enumeratii. Enumeratiile expun un enumerator care in C# este echivalentul unui iterator pentru parcurgerea colectiei. Un enumerator/iterator este un obiect care este legat de o instanta a unei colectii si urmareste pe ce pozitie a ramas in acea colectie pentru a implementa directive de parcurgere cum ar fi foreach.
📄️ LINQ
Inainte de a intra in detalii pentru LINQ, o sa facem o mica introducere in tipuri functionale. In majoritatea limbajelor OOP se suporta si aceste tipuri, puteti pasa functii la alte functii ca parametri sau sa returnati functii. In C# puteti folosi Func<TIn1, TIn2.., TIn14, TResult> (puteti avea 0 sau pana la 14 tipuri de intrare) pentru a reprezenta o functie care are o lista de parametri de tip TIn1, TIn2.., TIn14 si returneaza TResult, si Action<TIn1, TIn2.., TIn14> care este acealasi lucru doar ca nu returneaza nimic. Ambele tipuri sunt delegate-uri, practic sunt echivalentul in C# a pointerilor de functii. De asemenea, puteti declara functii inline, sau cum se numesc de fapt, functii lambada, ca de exemplu: