VB .NET - Realizando operações com List(of T)


Hoje vou mostrar como como realizar operações com coleção fortemente tipadas de objetos do tipo List(Of T).

A coleção genérica List(Of T) representa uma lista fortemente tipada de objetos que podem ser acessados através de um índice e fornece métodos para procurar(Search), ordenar(Sort) e manipular a lista.

Nota: O parâmetro (Of T) na declaração da lista é obrigatório e indica qual o tipo de dados que poderá ser incluído na coleção. ( A versão não genérica desta coleção e a classe ArrayList )

Neste artigo você vai aprender a :

Requisitos:

Objetivos

Criar e realizar as principais operações com uma coleção genérica List(Of T).

Criando o projeto no Visual Studio 2012 Express for desktop

Abra o Visual Studio 2012 Express for desktop e clique em New Project;

A seguir selecione o template Windows Forms Application, informe o nome OperacoesCom_List e clique em OK;

A seguir vamos incluir uma nova classe no projeto que representará o no nosso domínio e a partir da qual iremos criar a nossa coleção genérica do tipo desta classe.

No menu PROJECT clique em Add Class;

A seguir selecione o template Class, informe o nome Pessoa.vb e clique no botão Add e a seguir defina o seguinte código nesta classe:

Public Class Pessoa

    Public Property Id() As Integer
    Public Property Nome As String
    Public Property Sobrenome As String
    Public Property Idade() As Short
    Public Property Sexo As Nullable(Of Char)

    Public Sub New()
    End Sub

    Public Sub New(ByVal _id As Integer, ByVal _nome As String, ByVal _sobrenome As String, ByVal _idade As Short, ByVal _sexo As Char)
        Me.Id = _Id
        Me.Nome = _nome
        Me.Sobrenome = _sobrenome
        Me.Idade = _idade
        Me.Sexo = _sexo
    End Sub

End Class

A classe Pessoa define 5 propriedades e dois construtores sendo que um esta vazio e outro permite inicializar os valores das propriedades.

A seguir vamos incluir a partir da Toolbox os seguintes controles no formulário form1.vb:

Disponha os controles conforme o leiaute abaixo:

No início do formulário vamos declarar a variável listaPessoas ue será usada no projeto:

Dim listaPessoas As List(Of Pessoa)

Criando as rotinas de suporte às operações

Para criar uma lista de objetos Pessoa vamos usar a classe Pessoa e definir o no formulário form1.vb a seguinte rotina:

 Private Sub criarLista()
        listaPessoas = New List(Of Pessoa)()
        listaPessoas.Add(New Pessoa(1, "Jose Carlos", "Macoratti", 45, "M"c))
        listaPessoas.Add(New Pessoa(2, "Jefferson", "Jacobs", 19, "M"c))
        listaPessoas.Add(New Pessoa(3, "Miriam", "Agata", 25, "F"c))
        listaPessoas.Add(New Pessoa(4, "Janice", "Limeira", 18, "F"c))
        listaPessoas.Add(New Pessoa(5, "Lena", "Bianca", 33, "F"c))
        listaPessoas.Add(New Pessoa(6, "Susana", "Vieira", 45, "F"c))
        listaPessoas.Add(New Pessoa(7, "Jonas", "Buarque", 38, "M"c))
        listaPessoas.Add(New Pessoa(8, "Jane", "Hooks", 32, "F"c))
        listaPessoas.Add(New Pessoa(9, "Roberto", "Barros", 31, "M"c))
        listaPessoas.Add(New Pessoa(10, "Carlos", "Fogaça", 25, "F"c))
        listaPessoas.Add(New Pessoa(11, "Gina", "Pereira", 27, "F"c))
        listaPessoas.Add(New Pessoa(12, "Joel", "Vieira", 33, "M"c))
        listaPessoas.Add(New Pessoa(13, "George", "Douglas", 55, "M"c))
        listaPessoas.Add(New Pessoa(14, "Ricardo", "Benitez", 22, "M"c))
        listaPessoas.Add(New Pessoa(15, "Maria", "Silveira", 39, "F"c))
    End Sub

Vamos criar também uma rotina que será usada para exibir o resultado das operações no controle ListBox (lstbResultado) conforme o código a seguir:

Private Sub ExibirResultado(ByVal lista As List(Of Pessoa), ByVal info As String)
        lstbResultado.Items.Add(info)
        lstbResultado.Items.Add(vbCrLf)
        lstbResultado.Items.Add("ID" & vbTab & "Nome     " & vbTab & "Sobrenome" & vbTab & "Idade" & vbTab & "Sexo")
        lstbResultado.Items.Add(vbCrLf)
        For Each p As Pessoa In lista
            lstbResultado.Items.Add(p.Id & vbTab & p.Nome & vbTab & p.Sobrenome & vbTab & p.Idade & vbTab & p.Sexo)
        Next
        lstbResultado.Items.Add(vbCrLf)
End Sub

A rotina ExibirResultado() irá receber a lista genérica e uma texto que deverá ser exibido no controle ListBox.

1- Criando a lista genérica

Para criar a lista genérica de objetos Pessoa vamos incluir o código abaixo no evento Click do botão - Criar Lista de Pessoas :

 Private Sub btnCriarLista_Click(sender As Object, e As EventArgs) Handles btnCriarLista.Click
        Try
            criarLista()
            ExibirResultado(listaPessoas, "Lista de Pessoas - listaPessoas - criada com sucesso")
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message)
        End Try
    End Sub

O código cria uma lista genérica listaPessoas() usando a rotina CriarLista() e exibe a lista no ListBox na rotina ExibirResultado passando a lista e a informação desejada.

O resultado é visto abaixo:

2- Percorrendo a lista genérica

Para percorrer a lista chamamos a rotina ExibiResultado() no evento Click do botão - Percorrer Lista:

 Private Sub btnPercorreLista_Click(sender As Object, e As EventArgs) Handles btnPercorreLista.Click
        Try
            ExibirResultado(listaPessoas, "Percorrendo a Lista de Pessoas - listaPessoas - com sucesso")
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message)
        End Try
    End Sub

A lista é percorrida usando um laço For Each na lista genérica:

.....
   For Each p As Pessoa In lista
            lstbResultado.Items.Add(p.Id & vbTab & p.Nome & vbTab & p.Sobrenome & vbTab & p.Idade & vbTab & p.Sexo)
    Next
.....

3- Filtrando a Lista usando uma condição única

No evento Click do botão - Filtrar Lista - Condição única - temos o código abaixo:

Private Sub btnFiltrarListaCondUnica_Click(sender As Object, e As EventArgs) Handles btnFiltrarListaCondUnica.Click
        Try
            Dim listaFiltrada As List(Of Pessoa) = listaPessoas.FindAll(Function(p As Pessoa) p.Idade > 35)
            ExibirResultado(listaFiltrada, "3. --- Filtrando List(Of T) com uma condição (Idade > 35)")
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message)
        End Try
    End Sub

Estamos filtrando a lista usando o seguinte código:

Dim listaFiltrada As List(Of Pessoa) = listaPessoas.FindAll(Function(p As Pessoa) p.Idade > 35)

Onde temos:

listaPessoas.FindAll(Function(p As Pessoa) p.Idade > 35)

O método FindAll() - Recupera todos os elementos que coincidem com as condições definidas pelo predicado especificado, no caso uma consulta LINQ usando uma expressão lambda.

Function(p As Pessoa) p.Idade > 35 - é uma expressão lambda que estamos usando para realizar a consulta LINQ para retornar os objetos Pessoa com Idade > 35

As expressões lambdas são funções que podem conter expressões e declarações que são usadas para criar delegates e árvores de expressões onde o tipo das variáveis não precisam ser declarados visto que elas usam métodos anônimos.

O resultado é o seguinte:

4- Filtrando a Lista usando mais de uma condição

Podemos usar mais de uma condição para filtrar uma lista genérica. No evento Click do botão de comando - Filtrar Lista - Múltiplas Condições - temos o código que faz isso:

 Private Sub btnFiltrarListaMultCond_Click(sender As Object, e As EventArgs) Handles btnFiltrarListaMultCond.Click
        Try
            Dim listaFiltrada As List(Of Pessoa) = listaPessoas.FindAll(Function(p As Pessoa) p.Idade > 35 And p.Sexo = "F"c)
            ExibirResultado(listaFiltrada, "4. --- Filtrando List(Of T) com duas condições (Idade > 35 e Sexo Feminino)")
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message)
        End Try
    End Sub

Estamos filtrando a lista usando o seguinte código:

Dim listaFiltrada As List(Of Pessoa) = listaPessoas.FindAll(Function(p As Pessoa) p.Idade > 35 And p.Sexo = "F"c )

Onde temos:

listaPessoas.FindAll(Function(p As Pessoa) p.Idade > 35 And p.Sexo = "F"c)

O método FindAll() - Recupera todos os elementos que coincidem com as condições definidas pelo predicado especificado, no caso uma consulta LINQ usando uma expressão lambda.

Function(p As Pessoa) p.Idade > 35 And p.Sexo = "F"c - é uma expressão lambda que estamos usando para realizar a consulta LINQ para retornar os objetos Pessoa com Idade > 35 e Sexo Feminino.

O resultado é obtido é visto abaixo:

5- Ordenando uma lista genérica

Para ordernar uma lista genérica usamos o código a seguir no evento Click do botão - Ordernar Lista:

 Private Sub btnOrdenarLista_Click(sender As Object, e As EventArgs) Handles btnOrdenarLista.Click
        Dim listaOrdenadaPorNome As List(Of Pessoa) = listaPessoas
        listaOrdenadaPorNome.Sort(Function(p1 As Pessoa, p2 As Pessoa) p1.Nome.CompareTo(p2.Nome))
        ExibirResultado(listaOrdenadaPorNome, "5. --- Ordenar List(Of T) (Sort on Nome) ---")
    End Sub

O código define uma outra lista chamada listaOrdernadaPorNome com o mesmo conteúdo da nossa lista listaPessoas e aplica o método Sort na lista listaOrdernadaPorNome.

O método Sort classifica os elementos em todo o List (Of T) usando o comparador padrão. Por este motivo criamos outra lista idêntica a que já tínhamos no início.

Este método usa o comparador padrão Comparer(Of T) para determinar a ordem dos elementos da lista. A propriedade Comparer(Of T).Default verifica se o tipo T implementa a interface genérica IComparable(Of T) e usa essa implementação, se disponível. Se não ele verifica se o tipo T implementa a interface IComparable. Se o tipo T não implementa qualquer interface, Comparer(Of T).Default lança um InvalidOperationException.

Este método utiliza Array.Sort, que usa o algoritmo QuickSort. Esta implementação executa uma classificação instável, ou seja, se dois elementos são iguais, sua ordem não será preservada.(Uma ordenação estável preserva a ordem dos elementos que são iguais).

Abaixo vemos o resultado da ordenação:

6- Ordenando uma lista genérica - 2

Para ordenar uma lista genérica usamos o código a seguir no evento Click do botão - Ordernar Lista (2) :

 Private Sub btnOrdenarLista2_Click(sender As Object, e As EventArgs) Handles btnOrdenarLista2.Click
        Dim listaOrdenadaPorSobreNome As List(Of Pessoa) = listaPessoas
        listaOrdenadaPorSobreNome.Sort(Function(p1 As Pessoa, p2 As Pessoa) p2.Sobrenome.CompareTo(p1.Sobrenome))
        ExibirResultado(listaOrdenadaPorSobreNome, "6. --- Ordenar List(Of T) (Sort on Nome) ---")
    End Sub

O código define uma outra lista chamada listaOrdernadaPorSobreNome com o mesmo conteúdo da nossa lista listaPessoas e aplica o método Sort na lista listaOrdernadaPorSobreNome.

O método Sort classifica os elementos em todo o List(Of T) usando o comparador padrão. Por este motivo criamos outra lista idêntica a que já tínhamos no início.

O resultado é mostrado na figura abaixo:

7- Adicionando novos objetos na lista genérica

No evento Click do botão Adicionar Objetos na lista temos o código que permite incluir novos objetos na lista genérica do tipo Pessoa:

Private Sub btnAdicionarNaLista_Click(sender As Object, e As EventArgs) Handles btnAdicionarNaLista.Click
        Dim novaLista As List(Of Pessoa) = New List(Of Pessoa)()
        novaLista.Add(New Pessoa(16, "Teste", "Testolino", 29, "M"c))
        novaLista.Add(New Pessoa(17, "Testa", "Testolina", 32, "F"c))
        listaPessoas.AddRange(novaLista)
        ExibirResultado(listaPessoas, "7. --- Incluir novo objeto na lista List(Of T) a uma lista existente List() ---")
    End Sub

Definimos uma nova lista do mesmo tipo da nossa lista original, criamos novos objetos Pessoa e usamos o método AddRange para incluir os objetos na lista.

O método AddRange adiciona os elementos da coleção especificada ao fim da List(Of T) sendo que a ordem da coleção é preservada na lista.

Se o novo contador (Count) (o contador (Count) atual mais o tamanho da coleção) for maior do que a capacidade da lista (Capacity), a capacidade da List(Of T) será aumentada, realocando automaticamente a matriz interna para acomodar os elementos novos, e os elementos existentes são copiados para a nova matriz antes dos novos elementos serem adicionados.

A seguir vemos os novos elementos adicionados exibidos:

8- Removendo objetos da lista genérica

Para remover um objeto da lista usamos o método RemoveAll usando um critério que deverá ser verificado e atendido. No evento Click do botão - Remover itens da lista - temos o código que faz essa operação:

  Private Sub btnRemoverItemLista_Click(sender As Object, e As EventArgs) Handles btnRemoverItemLista.Click
        Dim removerLista As List(Of Pessoa) = listaPessoas
        removerLista.RemoveAll(Function(p As Pessoa) p.Sexo = "M"c)
        ExibirResultado(removerLista, "8. --- Remove mais de um item da lista ListOf T) baseado em uma condição ---")
    End Sub

O método RemoveAll remove todos os elementos que coincidem com as condições definidas pelo predicado especificado.

Public Function RemoveAll (criterio As Predicate(Of T)) As Integer

O Predicate(Of T) é um delegado para um método que retorna true se o objeto passado para ele coincide com as condições definidas no delegado. Os elementos List(Of T) atual são individualmente passados para o delegado Predicate(Of T) e os elementos que atendam às condições são removidos da List(Of T).

Esse método realiza uma pesquisa linear; Portanto, esse método é uma operação O(n) onde n é Count.

O resultado onde removemos todas as pessoas do sexo masculino da lista é exibido abaixo:

9 - Criando uma lista genérica somente-leitura

No botão - Criar Lista Somente-Leitura - temos o código onde criamos uma lista que não poderá ser modificada diretamente.

  Private Sub btnCriarListaSomenteLeitura_Click(sender As Object, e As EventArgs) Handles btnCriarListaSomenteLeitura.Click
        Dim pessoaSomenteLeitura As IList(Of Pessoa) = listaPessoas
        lstbResultado.Items.Add("Antes - Esta lista é somente-leitura ? True ou False : " & pessoaSomenteLeitura.IsReadOnly)
        pessoaSomenteLeitura = listaPessoas.AsReadOnly()
        lstbResultado.Items.Add("Depois - Esta lista é somente-leitura ? True ou False : " & pessoaSomenteLeitura.IsReadOnly)
    End Sub

O método AsReadOnly retorna um invólucro IList(Of T) somente leitura para a coleção atual. Para evitar quaisquer modificações na List(Of T), é exposta uma List(Of T) através de um invólucro.

Uma coleção que é somente leitura é simplesmente uma coleção com um invólucro que impede a modificação da coleção e, portanto, se forem feitas alterações na coleção subjacente, a coleção somente leitura reflete essas mudanças.

O código abaixo mostra o resultado após executarmos a operação com : listaPessoas.AsReadOnly()

Pegue o projeto completo aqui: OperacoesCom_List.zip

Mat 8:24 E eis que se levantou no mar tão grande tempestade que o barco era coberto pelas ondas; ele, porém, estava dormindo.

Mat 8:25 Os discípulos, pois, aproximando-se, o despertaram, dizendo: Salva-nos, Senhor, que estamos perecendo.

Mat 8:26 Ele lhes respondeu: Por que temeis, homens de pouca fé? Então, levantando-se repreendeu os ventos e o mar, e seguiu-se grande bonança.

Mat 8:27 E aqueles homens se maravilharam, dizendo: Que homem é este, que até os ventos e o mar lhe obedecem? (Jesus)

        Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti