C#  - Enumerable.Range revisitado


  Hoje vamos recordar o uso do método Enumerable.Range da linguagem C#.

O geração de sequências numéricas é uma tarefa comum, seja para laços, iterações, ou para inicializar coleções com valores padrão.

O C# fornece o método Enumerable.Range que gera uma sequência de números dentro de um intervalo especificado. Para isso ele usa o método estático Range() da classe Enumerable que esta no namespace System.Linq.

Sintaxe:

Enumerable.Range (int start, int count);

O retorno  é um IEnumerable<int> que contém a sequência gerada. Lembre-se de que cada número subsequente é incrementado em 1, o que também significa que os elementos estão em ordem crescente. No entanto, isso pode ser alterado com alguns truques do Linq (veremos isso mais adiante).

O método Range funciona com números inteiros e podemos fazê-lo funcionar também com floats.

Exemplos básico

Vamos começar com um exemplo bem básico: imprimir 50 números a partir do número 5 :

Resultado:

Gerando uma sequência na ordem reversa e descendente

Aqui você sente a simplicidade da Linq para fazer a reversão de uma sequência. Basta usar o método Reverse.

Confira o exemplo a seguir, que imprime os números de 10 a 1:

Resultado:

Gerando uma sequência de números pares/ímpares

Aqui para gerar o número de elementos esperados, definimos a quantidade, e usando o método Select, e aplicamos o critério desejado :

 var pares = Enumerable.Range(0, 10).Select(n => n * 2);

Ou podemos gerar um certo número de elementos e a seguir selecionamos apenas os que correspondem ao critério (pares ou ímpares) usando a cláusula Where:

var pares = Enumerable.Range(1, 20).Where(numero => numero % 2 == 0);

ou

var ímpares = Enumerable.Range(1, 20).Where(numero => numero % 2 == 1);

Resultados:

1- Gerando 10 números pares (Select)

2- Gerando 20 números e extraindo os números ímpares (Where)

Trabalhando com decimais

O recurso Enumerable.Range não funciona com floats apenas com inteiros.

Podemos contornar essa limitação usando um artifício.

No exemplo a seguir vamos gerar uma sequência de números de 1 até 2 com incremento de 0.1:

 var numeros = Enumerable.Range(10, 10).Select(numero => numero / 10f);

Aqui para cada número da sequência estamos dividindo por 10:

resultado:

Trabalhando com strings

Mas o melhor do método Range() é que você não precisa usá-lo apenas para produzir números, você pode usar a sequência que ele gera diretamente ou como ponto de partida para gerar uma expressão LINQ mais complexa.

Por exemplo, se quisermos gerar uma série de strings para tamanhos de fonte que desejamos usar podemos fazer isso facilmente:

var fontes = Enumerable.Range(1, 10).Select(i => (i * 10) + "pt").ToArray();

resultado:

Usando Range para gerar múltiplos objetos complexos

Outro uso do método Range() que ele pode ser útil é repetir alguma ação várias vezes.

Por exemplo, digamos que queremos criar e iniciar várias instâncias de uma Task (tarefa) para realizar algum trabalho em paralelo.

Poderíamos fazer isso usando uma alocação de um array padrão e a seguir uma laço loop for:

var NumeroTarefas = 10;

// constroi o array de um tamanho adequado
Task[] tasks = new Task[NumeroTarefas];

// percorre cada index e cria uma nova instância
for (int i = 0; i < NumeroTarefas; i++)
{ 
        tasks[i] = TaskFactory.StartNew("código");
}

Agora aplicando o método Range, resumimos o código acima em uma única expressão LINQ:

var NumeroTarefas = 10; 
Task[] tasks = Enumerable.Range(1, NumeroTarefas)
                       .Select(i => TaskFactory.StartNew("código"))
                      .ToArray();

Dessa forma o método Enumerable.Range() executa uma função muito simples, mas seus resultados podem ser usados para conduzir expressões LINQ muito mais complexas.

Manipulação avançada de sequências

O método Enumerable.Range() pode ser combinado com outros métodos LINQ, como Select, Where, e OrderBy, para manipulações mais avançadas

var quadradosPares = Enumerable.Range(1, 20)
                               .Where(n => n % 2 == 0)
                               .Select(n => n * n);
foreach (var quadrado in quadradosPares)
{
    Console.WriteLine(quadrado);
}

Vale mencionar que o método pode lançar exceções, como ArgumentOutOfRangeException, se o valor de count for negativo ou se a sequência exceder os limites de inteiros.

Sinta-se à vontade para usá-lo para gerar sequências inteiras simples e até sequências de uma ação repetida.

De qualquer forma, é um recurso que você deve conhecer sendo útil para gerar IDs sequencias para objetos, criar índices para acessar arrays ou listas e implementar paginadores de dados.

Pegue o código do projeto aqui:  CShp_Enumerable1.zip

"Não tenhas inveja dos homens malignos, nem desejes estar com eles.
Porque o seu coração medita a rapina, e os seus lábios falam a malícia."
Provérbios 24:1-2

Referências:


José Carlos Macoratti