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);
start - indica o início da sequência
count - indica quantos elementos serão gerados;
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:
C# - Tasks x Threads. Qual a diferença
C# - Programação Assíncrona como : Asycn e Task
C# - O Struct Guid - Macoratti.net