This article has been localized into Italian by the community.
Filtrare i dati: il metodo Where()
Una delle operazioni più elementari (nonché delle più potenti) che si possono effettuare su un insieme di dati è di filtrarlo. Abbiamo già dato un'occhiata a quello che si può fare con il metodo Where() nell'articolo introduttivo a LINQ, ma in questo articolo lo approfondiremo. Abbiamo già discusso di quanti metodi LINQ possono usare una espressione Lambda per eseguire le proprie operazioni e il metodo Where() è uno di questi. Fornisce ogni elemento come input e noi forniamo la logica che decide se l'elemento è incluso (ritorna true) o escluso (ritorna false) dal risultato finale. Ecco un esempio semplice:
List<int> numbers = new List<int>()
{
1, 2, 4, 8, 16, 32
};
var smallNumbers = numbers.Where(n => n < 10);
foreach (var n in smallNumbers)
Console.WriteLine(n);
In questo esempio, ogni numero è verificato dalla nostra espressione, che ritornerà true se il numero è minore di 10 e false se è 10 o maggiore. Come risultato, otteniamo una versione della lista originale, dove sono inclusi solo i numeri inferiori di 10, che vengono poi stampati nella console.
Ma l'espressione non deve essere necessariamente così semplice. Possiamo facilmente aggiungere altri requisiti, come se fosse una normale espressione if:
List<int> numbers = new List<int>()
{
1, 2, 4, 8, 16, 32
};
var smallNumbers = numbers.Where(n => n > 1 && n != 4 && n < 10);
foreach (var n in smallNumbers)
Console.WriteLine(n);
Specifichiamo che il numero deve essere maggiore di 1, ma non il numero 4 e minore di 10.
Si possono naturalmente usare diverse chiamate a metodi nell'espressione. Finché il risultato finale è un valore booleano, in modo che il metodo Where() capisca se si vuole o meno l'elemento in valutazione, si può fare. Ecco un esempio:
List<int> numbers = new List<int>()
{
1, 2, 4, 7, 8, 16, 29, 32, 64, 128
};
List<int> excludedNumbers = new List<int>()
{
7, 29
};
var validNumbers = numbers.Where(n => !excludedNumbers.Contains(n));
foreach (var n in validNumbers)
Console.WriteLine(n);
In questo esempio, dichiariamo una seconda lista di numeri, una sorta di lista nera di numeri che non vogliamo che vengano inclusi! Nel metodo Where(), usiamo il metodo Contains con la lista nera per decidere se un numero può essere incluso o meno nella lista finale di numeri.
E chiaramente, funziona anche per oggetti più complessi di numeri e stringhe, ed è comunque molto semplice da usare. Date un'occhiata a questo esempio, dove usiamo oggetti con informazioni utente al posto di numeri e usiamo il metodo Where() per ottenere una lista di utenti con nomi che iniziano con la lettera "J" e con età di 39 anni o meno.
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqWhere2
{
class Program
{
static void Main(string[] args)
{
List<User> listOfUsers = new List<User>()
{
new User() { Name = "John Doe", Age = 42 },
new User() { Name = "Jane Doe", Age = 34 },
new User() { Name = "Joe Doe", Age = 8 },
new User() { Name = "Another Doe", Age = 15 },
};
var filteredUsers = listOfUsers.Where(user => user.Name.StartsWith("J") && user.Age < 40);
foreach (User user in filteredUsers)
Console.WriteLine(user.Name + ": " + user.Age);
}
class User
{
public string Name { get; set; }
public int Age { get; set; }
}
}
}
E, tanto per confrontare, ecco come sarebbe l'operazione "where" se avessimo usato la sintassi di query invece di quella di metodo:
// Method syntax
var filteredUsers = listOfUsers.Where(user => user.Name.StartsWith("J") && user.Age < 40);
// Query syntax
var filteredUsersQ = from user in listOfUsers where user.Name.StartsWith("J") && user.Age < 40 select user;
Accodare diversi metodi Where()
Abbiamo discusso brevemente di questo nell'introduzione a LINQ: il risultato effettivo di una espressione LINQ non viene portato a compimento finché non si ha concretamente bisogno dei dati, ad esempio quando si cicla sul risultato (come facciamo nei nostri esempi) o lo si conteggia. Questo significa anche che si possono accodare diversi metodi Where() assieme, se si pensa che sia più facile da leggere. Con espressioni molto complesse, può certamente esserlo! Ecco una versione modificata del nostro esempio precedente:
List<int> numbers = new List<int>()
{
1, 2, 4, 8, 16, 32
};
var smallNumbers = numbers.Where(n => n > 1).Where(n => n != 4).Where(n => n < 10);
foreach (var n in smallNumbers)
Console.WriteLine(n);
Il risultato è esattamente lo stesso e mentre la prima versione non era così complessa da giustificare la suddivisione in diverse chiamate al metodo Where(), si incapperà in situazioni dove ha perfettamente senso farlo. Voglio sottolineare che questo non ha costi extra in termini di performance, perché le operazioni "where" effettive non vengono eseguite fino alla parte in cui si cicla sui risultati. Da quel punto, il compilatore e l'interprete avranno ottimizzato la query per essere la più veloce possibile, indipendentemente da come è stata scritta.
Riepilogo
Con il metodo Where() si possono filtrare elementi indesiderati dalla sorgente di dati, per creare un sottoinsieme dei dati originali. Ricordate che si ottiene un nuovo insieme di dati. I dati originali non saranno modificati, a meno che non si sovrascriva la variabile originale.