C# - Extensões para IEnumerable


  Hoje vou apresentar algumas extensões para a interface IEnumerable.

Na linguagem C#, IEnumerable continua sendo uma interface fundamental no .NET para representar uma sequência de elementos e fornece um mecanismo para iterar sobre esses elementos de forma genérica.

A interface IEnumerable  define um método chamado GetEnumerator() que permite percorrer sequencialmente os elementos da coleção usando um iterador.

Ela é  amplamente utilizada para representar e manipular coleções de elementos e permite a iteração sobre uma sequência de elementos, seja uma lista, um array, uma consulta LINQ ou qualquer outra estrutura de dados que implemente a interface IEnumerable.

Podemos estender as funcionalidades de IEnumerable por meios de métodos de extensão de forma bem simples.

A seguir vou apresentar alguns métodos de extensão de IEnumerable:

1-  Extensão para verificar se uma sequência está vazia

public static bool IsEmpty<T>(this IEnumerable<T> source)
{
 
foreach (var item in source)
  {
   
return false;
  }
 
return true;
}

Uso:

using CSharpExtensionsIEnumerable;

List<int> numeros = new List<int> { 1, 2, 3, 4, 5 };

bool isEmpty = numeros.IsEmpty();
 

2 - Extensão para filtrar elementos de uma sequência com base em um predicado

public static IEnumerable<T> Filter<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
  
foreach (var item in source)
   {
     
if (predicate(item))
      {
        
yield return item;
      }
   }
}

Uso:

List<int> numeros = new List<int> { 1, 2, 3, 4, 5 };

IEnumerable<int> numerosFiltrados = numeros.Filter(x => x % 2 == 0);
// Resultado: 2, 4

3 - Extensão para converter uma sequência em um dicionário usando uma chave seletora

public static Dictionary<TKey, TValue> ToDictionaryExt<T, TKey,
TValue>(this IEnumerable<T> source, Func<T, TKey> keySelector,
Func<T, TValue> valueSelector)
{
  
var dictionary = new Dictionary<TKey, TValue>();
  
foreach (var item in source)
   {
    
var key = keySelector(item);
    
var value = valueSelector(item);
     dictionary[key] = value;
   }
  
return dictionary;
}

Uso:

List<int> numeros = new List<int> { 1, 2, 3, 4, 5 };

Dictionary<
int, string> dicionario = numeros.ToDictionaryExt(x => x, x => $"Item {x}");
// Resultado: { 1: "Item 1" }, { 2: "Item 2" }, { 3: "Item 3" }, { 4: "Item 4" }, { 5: "Item 5" }

4-  Extensão para verificar se um tipo é nulo ou vazio

public static bool IsNullOrEmpty<T>(this IEnumerable<T>? source)
{
 
return source is null || !source.Any();
}

Uso:


var
result1 = Enumerable.Empty<int>().IsNullOrEmpty(); //true
var
result2 = new[] { 1, 2, 3 }.IsNullOrEmpty(); // false
var
result3 = ((IEnumerable<int>)null).IsNullOrEmpty(); // true
 

5- Extensão para particionar duas coleções

public static (IEnumerable<T1>, IEnumerable<T2>)
Partition<
T1, T2>(this IEnumerable<T1> source1, IEnumerable<T2> source2, int size)
{
   ArgumentNullException.ThrowIfNull(source1);
   ArgumentNullException.ThrowIfNull(source2);

  
var partition1 = source1.Take(size);
  
var partition2 = source2.Take(size);

  
return (partition1, partition2);
}

Essa extensão de método Partition recebe duas coleções de tipos diferentes (source1 e source2) e um parâmetro size que define o tamanho de cada partição.

Ela retorna um par de sequências particionadas, uma para source1 e outra para source2, onde cada sequência tem o tamanho especificado por size.

Uso:

List<int> inteiros = new List<int> { 1, 2, 3, 4, 5 };

List<string> frutas = new List<string> { "caju", "maça", "jaca", "kiwi", "uva" };

var particoes = inteiros.Partition(frutas, 3);
// Resultado: particoes.Item1 = { 1, 2, 3 }, particoes.Item2 = { "caju", "maça", "jaca" }
 

6-  Extensão para calcular a mediana de uma lista de números

public static double Mediana<T>(this IEnumerable<T> source) where T : IComparable<T>
{
  
var sortedList = source.OrderBy(x => x).ToList();
  
int count = sortedList.Count;

  
if (count == 0)
     
throw new InvalidOperationException("A lista está vazia.");

   
int mid = count / 2;

    if (count % 2 == 0)
    {
       T value1 = sortedList[mid - 1];
       T value2 = sortedList[mid];
      
return Convert.ToDouble(Convert.ToDouble(value1) + Convert.ToDouble(value2)) / 2;
    }
   
else
    {
     
return Convert.ToDouble(sortedList[mid]);
    }
}

Uso:

using CSharpExtensionsIEnumerable;

List<int> numeros = new List<int> { 4, 8, 15, 16, 23, 42 };

double mediana = numeros.Mediana();
// Resultado: 15.5

List<double> valores = new List<double> { 2.5, 4.7, 6.1, 8.2, 10.9 };
double
medianaDouble = valores.Mediana();
// Resultado: 6.1
 

Essa extensão de método calcula a mediana ordenando a lista e selecionando o valor do meio ou a média dos dois valores do meio, dependendo se a contagem da lista é ímpar ou par. É importante notar que a lista deve ser numérica e que o tipo T deve implementar a interface IComparable<T> para permitir a ordenação correta dos elementos.

Segue o código das extensões : CSharpExtensionsIEnumerable.zip

E estamos conversados.

"Em tudo somos atribulados, mas não angustiados; perplexos, mas não desanimados.
Perseguidos, mas não desamparados; abatidos, mas não destruídos;
Trazendo sempre por toda a parte a mortificação do Senhor Jesus no
corpo, para que a vida de Jesus se manifeste também no nosso corpo;"
2 Coríntios 4:8-10

Referências:


José Carlos Macoratti