CodeGym /Corsi /C# SELF /Filtraggio degli elementi

Filtraggio degli elementi

C# SELF
Livello 29 , Lezione 0
Disponibile

1. Modi base per filtrare le collezioni

Il filtraggio è come un setaccio per l'oro, solo che invece delle pepite scegliamo dalla collezione solo gli elementi che ci servono. Per esempio, abbiamo una lista di utenti — vogliamo trovare solo i maggiorenni, oppure solo gli studenti, oppure solo quelli che amano il caffè (insomma, i programmatori). Selezionare gli elementi giusti è una cosa che capita ovunque: dal lavoro con i DB alla gestione dell'input dell'utente.

Vediamo diversi modi per filtrare in C#. Man mano che impariamo, svilupperemo la nostra app console didattica aggiungendo filtri.

Filtraggio manuale con il ciclo

Partiamo dal modo più semplice e classico: filtrare con foreach:


// Esempio: abbiamo una lista di numeri, dobbiamo prendere solo i pari

List<int> numeri = new List<int> { 1, 2, 3, 4, 5, 6 };
List<int> numeriPari = new List<int>();

foreach (int numero in numeri)
{
    if (numero % 2 == 0) // se il numero è pari
    {
        numeriPari.Add(numero);
    }
}

Console.WriteLine("Numeri pari:");
foreach (int n in numeriPari)
{
    Console.WriteLine(n);
}

Questo metodo funziona sempre, è facile da capire, ma non è il più compatto e nemmeno il più "moderno".

Perché il filtraggio manuale non è sempre comodo?

Quando hai un'altra collezione, un altro criterio di filtro, o devi scrivere più filtri insieme — ti ritrovi con tanto codice simile. Vorresti più compattezza, leggibilità e modularità.

2. Filtraggio con criteri complessi

Supponiamo di avere una collezione di oggetti. Prendiamo l'esempio degli utenti dalla nostra app in sviluppo.


public class User
{
    public string Nome { get; set; }
    public int Eta { get; set; }
    public bool EStudente { get; set; }
}

Dichiariamo una lista di utenti:


List<User> utenti = new List<User>
{
    new User { Nome = "Anja", Eta = 17, EStudente = true },
    new User { Nome = "Boris", Eta = 21, EStudente = false },
    new User { Nome = "Vika", Eta = 19, EStudente = true },
    new User { Nome = "Gleb", Eta = 25, EStudente = false }
};

Esempio 1: Selezionare tutti gli studenti


List<User> studenti = new List<User>();
foreach (User utente in utenti)
{
    if (utente.EStudente)
        studenti.Add(utente);
}

Console.WriteLine("Lista degli studenti:");
foreach (User utente in studenti)
{
    Console.WriteLine($"{utente.Nome} ({utente.Eta})");
}

Esempio 2: Selezionare solo gli studenti maggiorenni


List<User> maggiorenni = new List<User>();
foreach (User utente in utenti)
{
    if (utente.Eta >= 18 && utente.EStudente)
        maggiorenni.Add(utente);
}

Console.WriteLine("Studenti maggiorenni:");
foreach (User utente in maggiorenni)
{
    Console.WriteLine($"{utente.Nome} ({utente.Eta})");
}

E se i criteri di filtro sono dinamici?

Puoi mettere le condizioni di filtro in metodi separati, così li richiami dentro il ciclo:


bool EMaggiore(User u) { return u.Eta >= 18; }
bool EStudente(User u) { return u.EStudente; }

List<User> filtrati = new List<User>();
foreach (User utente in utenti)
{
    if (EMaggiore(utente) && EStudente(utente))
        filtrati.Add(utente);
}

3. Filtraggio per chiave nei dizionari

Liste e array sono comodi, ma spesso lavoriamo anche con i dizionari.

Supponiamo di avere un dizionario dove la chiave è il nome dell'utente e il valore è la sua età:


Dictionary<string, int> etaPerNome = new Dictionary<string, int>
{
    ["Anja"] = 17,
    ["Boris"] = 21,
    ["Vika"] = 19,
    ["Gleb"] = 25
};

Obiettivo: selezionare solo utenti 18+


Dictionary<string, int> maggiorenni = new Dictionary<string, int>();
foreach (var coppia in etaPerNome)
{
    if (coppia.Value >= 18)
        maggiorenni.Add(coppia.Key, coppia.Value);
}

Console.WriteLine("Maggiorenni:");
foreach (var coppia in maggiorenni)
{
    Console.WriteLine($"{coppia.Key}: {coppia.Value} anni");
}

Obiettivo: selezionare utenti con nomi che iniziano per "V"


Dictionary<string, int> nomiConV = new Dictionary<string, int>();
foreach (var coppia in etaPerNome)
{
    if (coppia.Key.StartsWith("V"))
        nomiConV.Add(coppia.Key, coppia.Value);
}

Console.WriteLine("Nomi che iniziano con 'V':");
foreach (var coppia in nomiConV)
{
    Console.WriteLine($"{coppia.Key}: {coppia.Value} anni");
}

4. Principi del filtraggio

Come funziona il processo di filtraggio


┌──────────────────────────────────┐
│  Lista: [1, 2, 3, 4, 5, 6]       │
└──────────────────────────────────┘
         │
         ▼
    [Controllo: n % 2 == 0]
         │
         ▼
┌──────────────────────────────────┐
│  Risultato: [2, 4, 6]            │
└──────────────────────────────────┘

Composizione dei filtri: filtrare con condizioni diverse

Puoi fare filtraggi in sequenza, se vuoi selezionare i dati a step:


// Prima filtriamo solo gli studenti
List<User> soloStudenti = new List<User>();
foreach (User utente in utenti)
{
    if (utente.EStudente)
        soloStudenti.Add(utente);
}

// Poi tra loro scegliamo solo i maggiorenni
List<User> studentiMaggiorenni = new List<User>();
foreach (User utente in soloStudenti)
{
    if (utente.Eta >= 18)
        studentiMaggiorenni.Add(utente);
}

Oppure tutto insieme:


List<User> studentiMaggiorenni = new List<User>();
foreach (User utente in utenti)
{
    if (utente.EStudente && utente.Eta >= 18)
        studentiMaggiorenni.Add(utente);
}

Ordinamento e altre operazioni

L'ordinamento si fa con il metodo Sort per le liste:


// Studenti maggiorenni ordinati per età
studentiMaggiorenni.Sort((a, b) => a.Eta.CompareTo(b.Eta));

Parleremo meglio dell'ordinamento nella prossima lezione!

5. Filtraggio negli scenari utente

1. Filtraggio dell'input utente

Supponiamo che la nostra app riceva una lista di voti e debba selezionare tutti i "cinque".


Console.Write("Inserisci i voti separati da spazio: ");
string input = Console.ReadLine();

List<int> voti = new List<int>();
foreach (string s in input.Split(' '))
{
    if (int.TryParse(s, out int voto))
        voti.Add(voto);
}

List<int> cinque = new List<int>();
foreach (int voto in voti)
{
    if (voto == 5)
        cinque.Add(voto);
}

Console.WriteLine("Cinque:");
foreach (var voto in cinque)
{
    Console.WriteLine(voto);
}

2. Filtraggio con più condizioni

Obiettivo: selezionare utenti-studenti con età da 18 a 22 anni inclusi.


List<User> filtrati = new List<User>();
foreach (User utente in utenti)
{
    if (utente.EStudente && utente.Eta >= 18 && utente.Eta <= 22)
        filtrati.Add(utente);
}

3. Filtraggio per presenza di un elemento

Abbiamo una lista di stringhe e vogliamo selezionare solo quelle che contengono la sottostringa ".net" (senza distinzione tra maiuscole e minuscole).


List<string> tecnologie = new List<string> { "C#", ".NET", "Java", "dotnet", "JavaScript" };

List<string> netTechs = new List<string>();
foreach (var tech in tecnologie)
{
    if (tech.ToLower().Contains(".net"))
        netTechs.Add(tech);
}

foreach (var tech in netTechs)
{
    Console.WriteLine(tech);
}

6. Caratteristiche e errori tipici nel filtraggio

Il filtraggio sembra facile, ma qui si può fare casino. Vediamo alcune particolarità.

Modifica della collezione originale

Se filtri la collezione originale e poi la cambi dopo il filtraggio, — il risultato non cambia, se hai già creato una nuova lista. Se invece hai solo salvato il riferimento alla vecchia lista, i cambiamenti nella collezione originale possono influenzare il risultato.


List<int> filtrati = new List<int>();
foreach (int n in numeri)
{
    if (n > 2)
        filtrati.Add(n);
}

// Modifichiamo la lista originale
numeri.Add(10);

foreach (var n in filtrati)
{
    Console.WriteLine(n); // 10 non ci sarà
}

Risultato del filtraggio manuale

Il risultato del filtraggio manuale di solito è una nuova lista modificabile (tipo List<T>), con cui puoi fare tutto quello che vuoi — aggiungere, togliere elementi ecc.

Filtraggio e performance

I filtri nei cicli vengono chiamati per ogni elemento della collezione, quindi se la funzione dentro la condizione è pesante — occhio. A volte è meglio fare un semplice ciclo foreach, soprattutto se hai logica complessa e ti serve fare logging o altre azioni.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION