CodeGym /Corsi /C# SELF /Lavorare avanzato con gli array

Lavorare avanzato con gli array

C# SELF
Livello 7 , Lezione 2
Disponibile

1. Array di tipo string

Allora, giusto due parole sull’array di tipo string.

Come abbiamo già detto, un array può essere di qualsiasi tipo. Quindi, puoi creare un array di tipo string. Ecco come sarebbe il codice se dovessimo scrivere un programma che “legge da tastiera 10 stringhe e le stampa a schermo in ordine inverso”.

string[] array = new string[10];	// Creiamo un oggetto-array da 10 elementi
for (int i = 0; i < 10; i++)		// Ciclo da 0 a 9
{
   array[i] = Console.ReadLine();	// Leggiamo una stringa da tastiera e la salviamo nella cella dell’array
}
for (int i = 9; i >= 0; i--)		// Ciclo da 9 a 0
{
    Console.WriteLine(array[i]);	// Stampiamo a schermo la cella corrente dell’array
}

Il codice praticamente non è cambiato! Abbiamo solo dovuto cambiare il tipo int in string quando abbiamo creato l’array. Per il resto, tutto uguale!

2. Array di tipo string in memoria

E ancora una cosa utile. Guarda queste 3 immagini:

Immagine 1. Come un oggetto string è posizionato in memoria:

Array di tipo string in memoria

Nota che il testo della stringa non viene salvato direttamente nella variabile: per lui viene riservato un blocco di memoria separato. E nella variabile di tipo string viene salvato l’indirizzo (il riferimento) all’oggetto con il testo.

Immagine 2. Come un array di numeri interi è posizionato in memoria:

int array in memory

Anche questa immagine l’hai già vista.

Immagine 3. Come un array di stringhe è posizionato in memoria:

How a string array is stored in memory

A sinistra vediamo la variabile-array di tipo string[] (contiene l’indirizzo dell’oggetto-array).
Al centro — l’oggetto-array di tipo string.
A destra — gli oggetti-stringa che contengono i testi.

Nelle celle dell’oggetto-array di tipo string non ci sono le stringhe stesse (i testi), ma i loro indirizzi (riferimenti). Proprio come nelle variabili di tipo string ci sono gli indirizzi delle stringhe (testo).

3. Inizializzazione veloce di un array in C#

Gli array sono una cosa super utile, quindi gli sviluppatori di C# hanno cercato di renderli il più comodi possibile. E la prima cosa che hanno fatto è stata semplificare l’inizializzazione dell’array, cioè inserire i valori iniziali.

Spesso, oltre ai dati che il programma legge da qualche parte, servono anche dati interni. Per esempio, dobbiamo salvare in un array le lunghezze di tutti i mesi. Come potrebbe essere questo codice:

int[] months = new int[12];
months[0] = 31; // gennaio
months[1] = 28; // febbraio
months[2] = 31; // marzo
months[3] = 30; // aprile
months[4] = 31; // maggio
months[5] = 30; // giugno
months[6] = 31; // luglio
months[7] = 31; // agosto
months[8] = 30; // settembre
months[9] = 31; // ottobre
months[10] = 30; // novembre
months[11] = 31; // dicembre

Ma c’è un modo per scriverlo più corto — grazie agli sviluppatori di C#:

// lunghezze dei mesi dell’anno
int[] months = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

Basta elencare tutti i valori dell’array separati da virgola!

Comodo, vero? Ma non è tutto.

Il compilatore può capire il tipo del contenitore (l’oggetto-array) dal tipo della variabile-array. E per capire la lunghezza dell’array — semplicemente conta quanti elementi ci sono tra le parentesi graffe.

Quindi questo codice si può scrivere ancora più corto:

// lunghezze dei mesi dell’anno
int[] months = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

Non è una figata? 🙂

Questa scrittura si chiama “inizializzazione veloce dell’array”. E funziona non solo per il tipo int...

// nomi dei mesi dell’anno
string[] months = { "Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"};

4. Il ciclo foreach

Scorrere tutti gli elementi di un array è un’operazione così frequente che hanno inventato un ciclo apposta(!). Si chiama foreach. E si scrive così:


foreach (int score in scores)
{
    Console.WriteLine($"Punti: {score}");
}
        
Scorrere gli elementi di un array con foreach

Qui il ciclo scorre da solo gli elementi ― nessun indice manuale. Non puoi modificare direttamente gli elementi (sono disponibili solo in lettura nel ciclo), ma è super comodo per “passare” sull’array.

Il compilatore trasforma il codice del ciclo foreach in questo codice qui sotto:


for (int i = 0; i < scores.Length; i++)
{
    int score = scores[i];
    Console.WriteLine($"Punti: {score}");
}
        
Come funziona foreach “sotto il cofano”

Quindi niente magia. Ora è chiaro perché non puoi modificare gli elementi dell’array tramite la variabile score.

Facciamo un altro esempio: troviamo la somma di tutti i punti.


int sum = 0;
foreach (int score in scores)
{
    sum += score;
}
Console.WriteLine($"Somma di tutti i punti: {sum}");
        
Sommare gli elementi di un array con foreach

Quando usare quale ciclo?

  • Se ti serve l’indice o vuoi modificare gli elementi — usa il ciclo for.
  • Se vuoi solo scorrere i valori — foreach è più veloce e pulito.

5. Indicizzazione dalla fine: operatore ^

Da un po’ di tempo in C# puoi prendere gli elementi dalla fine dell’array. Prima, se volevi l’ultimo elemento dell’array, scrivevi qualcosa tipo:


int lastScore = scores[scores.Length - 1];
        
Prendere l’ultimo elemento dell’array alla vecchia maniera

Ora è molto più semplice. Basta mettere l’operatore ^ davanti all’indice, e il conteggio parte dalla fine:


int lastScore = scores[^1];        // Ultimo elemento
int penultimate = scores[^2];      // Penultimo elemento
        
Indicizzazione dalla fine con ^
  • ^1 — è il primo dalla fine (l’ultimo).
  • ^2 — è il secondo dalla fine.

Visualizzazione

Indice Valore nell’array scores Indice normale Indice dalla fine
0 10 0 ^5
1 15 1 ^4
2 8 2 ^3
3 22 3 ^2
4 17 4 ^1

score[^1] = 17, score[^2] = 22 — facile e chiaro.

Importante! Nota che gli indici dalla fine partono da 1, non da zero.

6. Range: operatore .. (range)

A volte serve ottenere un sotto-array dall’array originale. In C# puoi usare l’operatore speciale di range .. — è un modo compatto e super comodo per prendere il “pezzo” che ti serve dell’array.

Questo sotto-array a volte viene chiamato slice (dall’inglese "slice"), ed è definito da due limiti: inizio e fine.
Attenzione: il limite destro non è incluso nel risultato!

Come si presenta


int[] scores = { 10, 15, 8, 22, 17 };
int[] top3 = scores[0..3]; // Prendiamo gli elementi da 0 a 2: {10, 15, 8}
        
Prendere uno slice dell’array con ..

  • scores[0..3] — prendiamo gli elementi dall’indice 0 (incluso) all’indice 3 (NON incluso).
  • L’array finale conterrà gli elementi con indici 0, 1 e 2.

Abbreviazioni

Se non specifichi il limite sinistro, prendi dall’inizio:


int[] firstTwo = scores[..2]; // uguale a scores[0..2], cioè {10, 15}
        

Se non specifichi il limite destro, prendi fino alla fine:


int[] fromThird = scores[2..]; // {8, 22, 17}
        

Indici negativi

Con il simbolo ^ puoi contare gli indici dalla fine:


int[] lastTwo = scores[^2..]; // {22, 17}
        

Qui ^2 — è il “secondo elemento dalla fine”.

Puoi anche prendere un range “da a”, usando indici negativi su entrambi i lati:


int[] mid = scores[1..^1]; // {15, 8, 22} (dal secondo al penultimo)
        

Cosa ricordare

  • Il limite destro non è mai incluso — cioè se scrivi a..b, prendi tutti gli elementi da a a b-1.
  • Se metti limiti fuori dall’array, viene lanciata un’eccezione IndexOutOfRangeException.
  • Lo slice — è un nuovo array, l’originale non cambia. Qualsiasi modifica nel nuovo array non tocca quello originale.

Esempi pratici

int[] arr = { 1, 2, 3, 4, 5, 6, 7 };
int[] arr = { 1, 2, 3, 4, 5, 6, 7 };

int[] start = arr[..3];      // {1, 2, 3}
int[] end = arr[^2..];       // {6, 7}
int[] middle = arr[2..5];    // {3, 4, 5}
int[] all = arr[..];         // {1, 2, 3, 4, 5, 6, 7} (copia completa)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION