Alura > Cursos de Mobile > Cursos de Flutter > Conteúdos de Flutter > Primeiras aulas do curso Praticando Collections no Dart: listas, sets e mapas

Praticando Collections no Dart: listas, sets e mapas

Praticando Collections no Dart: listas, sets e mapas - Praticando Collections no Dart: listas, sets e mapas

Olá! Meu nome é Mikael, sou instrutor na Alura, e quero dar as boas-vindas ao curso de Praticando com Dart!.

Audiodescrição: Mikael se descreve como um homem de pele preta e cabelo crespo. Veste uma camiseta lisa na cor preta e está em um ambiente de cor azul.

Introdução

Neste curso, exploraremos as collections no Dart, abordando o funcionamento de listas, sets e mapas. Utilizaremos o Dart Pad como ambiente de desenvolvimento.

Para começar, escolha o navegador de sua preferência e acesse dartpad.dev. Esse será o ambiente onde desenvolveremos e executaremos o programa ao longo do curso.

Ao acessar o DartPad, você verá um código inicial que será descartado, pois construiremos nosso programa do zero. A proposta é criar uma simulação de envio de e-mails.

Criando a Função enviarEmail()

Iniciaremos com a criação de uma função responsável por simular o envio de e-mails. Essa função será do tipo void, pois não retornará nenhum valor, e será chamada enviarEmail(). Ela receberá um parâmetro do tipo String, representando o e-mail a ser enviado. Em seguida, exibirá uma mensagem no terminal indicando que uma mensagem foi enviada para o e-mail informado.

void enviarEmail(String email){
    print('mensagem enviada para: $email');
}

Implementando a Função main()

Com a função enviarEmail() criada, o próximo passo é desenvolver a função main(), que será responsável por executar nosso código. A função main() também será do tipo void e não receberá parâmetros.

Dentro dela, declararemos duas variáveis do tipo String:

Testando o Código Inicial

Em seguida, utilizaremos a função enviarEmail() para enviar mensagens para esses endereços de e-mail, passando joaoEmail e mariaEmail como parâmetros.

void enviarEmail(String email){
    print('mensagem enviada para: $email');
}

void main(){
    String joaoEmail = 'joao@gmail.com';
    String mariaEmail ='maria@gmail.com';
    
    enviarEmail(joaoEmail);
    enviarEmail(mariaEmail);
}

Após criar as variáveis e utilizar a função de envio de e-mail, podemos testar o código clicando no botão "Run". Ao executar, serão exibidas as mensagens:

mensagem enviada para: joao@gmail.com

mensagem enviada para: maria@gmail.com

Isso indica que a função está funcionando corretamente.

Trabalhando com Listas

No entanto, se precisarmos enviar mensagens para uma grande quantidade de e-mails, como cem ou mil, o uso de variáveis individuais não será eficiente. Criar mil variáveis e chamar a função de envio de e-mail manualmente para cada uma delas geraria muito retrabalho.

É nesse cenário que as collections se tornam indispensáveis, pois oferecem uma estrutura eficiente para manipular grandes quantidades de dados de forma organizada e prática.

Vamos agora implementar uma lista no programa de envio de e-mails. Para isso, criaremos uma lista utilizando a classe List, especificando que ela armazenará valores do tipo String. Nomearemos essa lista como listaEmails, que inicialmente estará vazia.

void enviarEmail(String email){
    print('mensagem enviada para: $email');
}

void main(){
    String joaoEmail = 'joao@gmail.com';
    String mariaEmail ='maria@gmail.com';
    
    enviarEmail(joaoEmail);
    enviarEmail(mariaEmail);

List<String> listaEmails = [];
}

Para adicionar valores à lista, utilizaremos vírgulas para separar os elementos. Nesse caso, incluiremos os e-mails joao@gmail.com e maria@gmail.com na listaEmails.

void enviarEmail(String email){
    print('mensagem enviada para: $email');
}

void main(){
    String joaoEmail = 'joao@gmail.com';
    String mariaEmail ='maria@gmail.com';
    
    enviarEmail(joaoEmail);
    enviarEmail(mariaEmail);

List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];
}

Com os e-mails armazenados na lista, podemos eliminar as variáveis individuais que usávamos anteriormente.

void enviarEmail(String email){
    print('mensagem enviada para: $email');
}

void main(){
List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];
}

Acessando Elementos da Lista por Índice

Para acessar os elementos da lista, utilizaremos índices. Para exibir joao@gmail.com, que está na primeira posição, utilizaremos a função print passando listaEmails[] com o índice 0 entre colchetes.

Quando o elemento está na primeira posição da lista, seu índice é 0. Quando está na segunda posição, o índice é 1. Na terceira, é 2. Na quarta, é 3, e assim sucessivamente.

void enviarEmail(String email){
    print('mensagem enviada para: $email');
}

void main(){
List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

print(listaEmails[0]);
}

Ao executar, obtemos joao@gmail.com. Para exibir maria@gmail.com basta seguir o mesmo processo utilizando o índice 1.

void enviarEmail(String email){
    print('mensagem enviada para: $email');
}

void main(){
List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

print(listaEmails[1]);
}

Enviando E-mails Usando um Laço for

No entanto, ainda precisamos de uma forma eficiente de enviar e-mails para todos os elementos da lista sem chamar a função manualmente para cada posição. Para isso, utilizaremos um laço for, que percorrerá a listaEmails.

O laço funcionará da seguinte forma: para cada String email presente em listaEmails, chamaremos o método print. Dessa maneira, todos os e-mails da lista serão impressos.

void enviarEmail(String email){
    print('mensagem enviada para: $email');
}

void main(){
List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

    for(String email in listaEmails){
        print(email);
    }
}

Após implementar essa solução, podemos testar o código clicando em "Run". Se tudo estiver correto, veremos os emails joao@gmail.com e maria@gmail.com no terminal.

Nosso objetivo não é apenas exibir os e-mails, mas também enviar uma mensagem para cada um deles. Para isso, substituiremos a função print pela função enviarEmail.

void enviarEmail(String email){
    print('mensagem enviada para: $email');
}

void main(){
List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

    for(String email in listaEmails){
        enviarEmail(email);
    }
}

Ao executar o código, obtemos o retorno de mensagem enviada para cada um dos emails:

mensagem enviada para: joao@gmail.com

mensagem enviada para: maria@gmail.com

Adicionando Valores à Lista

Além dos valores iniciais que declaramos na lista, como os e-mails de João e Maria, queremos adicionar outros valores, como o e-mail do Enzo. Para adicionar um novo valor, utilizamos os métodos da lista.

Métodos são funcionalidades que facilitam a execução de operações com nossas collections. Eles estão disponíveis tanto para listas quanto para sets e mapas, que vamos explorar mais adiante.

No caso das listas, para adicionar um elemento, usamos o método add. Ou seja, para adicionar o e-mail do Enzo, basta escrever listaEmails.add(), e dentro dos parênteses, passar o valor que queremos adicionar, enzo@gmail.com.

void enviarEmail(String email){
    print('mensagem enviada para: $email');
}

void main(){
List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

listaEmails.add('enzo@gmail.com');

    for(String email in listaEmails){
        enviarEmail(email);
    }
}

Ao executar o código, a mensagem também é enviada para o novo email adicionado:

mensagem enviada para: joao@gmail.com

mensagem enviada para: maria@gmail.com

mensagem enviada para: enzo@gmail.com

Utilizando o Método contains

É possível que, por um erro de digitação, um email já existente seja adicionado novamente à lista, causando duplicidade. Para evitar esse problema, podemos utilizar o método contains antes de adicionar um novo e-mail.

Em uma condicional if utilizaremos esse método para verificar se o e-mail já está presente na lista. Se não estiver, utilizamos o método add para incluí-lo.

void enviarEmail(String email){
    print('mensagem enviada para: $email');
}

void main(){
List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

listaEmails.add('enzo@gmail.com');

if(listaEmails.contains('enzo@gmail.com')==false){
    listaEmails.add('enzo@gmail.com');
}

    for(String email in listaEmails){
        enviarEmail(email);
    }
}

Ao executar, o código funciona corretamente e obtemos o seguinte retorno:

mensagem enviada para: joao@gmail.com

mensagem enviada para: maria@gmail.com

mensagem enviada para: enzo@gmail.com

Otimizando com Sets

Embora o contains seja eficiente em listas pequenas, ele percorre toda a lista para verificar a existência do e-mail. Em listas grandes, isso pode afetar o desempenho. Nesse caso, uma solução mais eficiente é utilizar um set.

A declaração de um set é semelhante à de uma lista, mas utilizamos Set em vez de List. No nosso caso, especificaremos que o set armazenará valores do tipo String e o nomearemos como setEmails. Inicializamos o set utilizando chaves {}.

Antes de continuar, vamos comentar parte do código anterior e focar apenas na utilização do set.

void enviarEmail(String email){
    print('mensagem enviada para: $email');
}

void main(){
// List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

// listaEmails.add('enzo@gmail.com');

// if(listaEmails.contains('enzo@gmail.com')==false){
// 	listaEmails.add('enzo@gmail.com');
// }

// 	for(String email in listaEmails){
// 		enviarEmail(email);
// 	}
 
  Set<String> setEmails = {};
  
}

Para inicializar nosso set, seguimos o mesmo processo que usamos com a lista: passamos os elementos separados por vírgula.

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

  // listaEmails.add('enzo@gmail.com');

  // if(listaEmails.contains('enzo@gmail.com')==false){
  // 	listaEmails.add('enzo@gmail.com');
  // }

  // 	for(String email in listaEmails){
  // 		enviarEmail(email);
  // 	}

  Set<String> setEmails = {'joao@gmail.com', 'maria@gmail.com'};
}

Iterando sobre o Set

Com isso, podemos começar a utilizar o set e testar algumas operações. A primeira coisa que vamos fazer é percorrer os e-mails armazenados e imprimi-los. Para isso, usaremos novamente o laço de repetição for. A sintaxe será:

for(String email in setEmails) {
  print(email);
}

Código completo:

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

  // listaEmails.add('enzo@gmail.com');

  // if(listaEmails.contains('enzo@gmail.com')==false){
  // 	listaEmails.add('enzo@gmail.com');
  // }

  // 	for(String email in listaEmails){
  // 		enviarEmail(email);
  // 	}

  Set<String> setEmails = {'joao@gmail.com', 'maria@gmail.com'};

  for (String email in setEmails) {
    print(email);
  }
}

Ao executar, obtemos os emails joao@gmail.com e maria@gmail.com.

Adicionando Valores ao Set

Os elementos são adicionados ao set da mesma forma que na lista, com o método add. Portanto, adicionaremos o email enzo@gmail.com:

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

  // listaEmails.add('enzo@gmail.com');

  // if(listaEmails.contains('enzo@gmail.com')==false){
  // 	listaEmails.add('enzo@gmail.com');
  // }

  // 	for(String email in listaEmails){
  // 		enviarEmail(email);
  // 	}

  Set<String> setEmails = {'joao@gmail.com', 'maria@gmail.com'};
  
  setEmails.add('enzo@gmail.com');
  
  for (String email in setEmails) {
    print(email);
  }
}

Ao executar, obtemos os 3 e-mails: joao@gmail.com, maria@gmail.com e enzo@gmail.com.

Verificando a Duplicidade no Set

Em seguida, faremos um teste para verificar o comportamento do set ao tentarmos adicionar o mesmo e-mail duas vezes.

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

  // listaEmails.add('enzo@gmail.com');

  // if(listaEmails.contains('enzo@gmail.com')==false){
  // 	listaEmails.add('enzo@gmail.com');
  // }

  // 	for(String email in listaEmails){
  // 		enviarEmail(email);
  // 	}

  Set<String> setEmails = {'joao@gmail.com', 'maria@gmail.com'};
  
  setEmails.add('enzo@gmail.com');
  
  setEmails.add('enzo@gmail.com');

  
  for (String email in setEmails) {
    print(email);
  }
}

Ao executar, obtemos os 3 e-mails: joao@gmail.com, maria@gmail.com e enzo@gmail.com.

Em uma lista, isso resultaria em duplicação, mas no set, o e-mail não será duplicado. Isso ocorre porque o set evita automaticamente elementos repetidos, o que o torna ideal para situações em que a unicidade dos dados é essencial.

Verificando Valores no Set

Para verificar se um e-mail específico está presente no set, utilizamos o método contains. Por exemplo, ao verificar a presença do e-mail do Enzo, a função retornará true se ele estiver no set. Caso contrário, exibiremos uma mensagem informando que o e-mail não foi encontrado.

Antes de testar o código, removeremos o laço de repetição para evitar duplicidades na saída.

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

  // listaEmails.add('enzo@gmail.com');

  // if(listaEmails.contains('enzo@gmail.com')==false){
  // 	listaEmails.add('enzo@gmail.com');
  // }

  // 	for(String email in listaEmails){
  // 		enviarEmail(email);
  // 	}

  Set<String> setEmails = {'joao@gmail.com', 'maria@gmail.com'};

  setEmails.add('enzo@gmail.com');

  setEmails.add('enzo@gmail.com');

  if (setEmails.contains('enzo@gmail.com') == true) {
    print('email de enzo dentro do set');
  } else {
    print('não está dentro do set');
  }
}

Ao executar, confirmamos que o e-mail do Enzo está presente no set. Se alterarmos a verificação para enzod@gmail.com, o programa exibirá uma mensagem informando que o e-mail não está no set.

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // List<String> listaEmails = ['joao@gmail.com', 'maria@gmail.com'];

  // listaEmails.add('enzo@gmail.com');

  // if(listaEmails.contains('enzo@gmail.com')==false){
  // 	listaEmails.add('enzo@gmail.com');
  // }

  // 	for(String email in listaEmails){
  // 		enviarEmail(email);
  // 	}

  Set<String> setEmails = {'joao@gmail.com', 'maria@gmail.com'};

  setEmails.add('enzo@gmail.com');

  setEmails.add('enzo@gmail.com');

  if (setEmails.contains('enzod@gmail.com') == true) {
    print('email de enzo dentro do set');
  } else {
    print('não está dentro do set');
  }
}

Esse comportamento destaca a importância de atenção aos detalhes na escrita dos e-mails.

Além do método add e da prevenção de duplicidade, o set oferece vantagens de desempenho em operações de busca, pois não precisa percorrer todos os elementos como acontece nas listas.

Associando Valores com Map

Agora, vamos explorar o uso de maps.

Suponha que, além dos e-mails, queremos associar um nome a cada pessoa. Para isso, utilizamos um map, onde cada chave representa um nome e cada valor armazena o e-mail correspondente.

Vamos comentar o código utilizado e criar um Map chamado pessoasEmails, especificando que tanto as chaves quanto os valores serão do tipo String. Inicializamos o map com pares de chave e valor, como joao associado a joao@gmail.com. Faremos o mesmo para a Maria, associando o nome ao e-mail maria@gmail.com:

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // código comentado

  Map<String, String> pessoasEmails = {
    'joao': 'joao@gmail.com',
    'maria': 'maria@gmail.com',
  };
}

Acessando Valores no Map

Para acessar um valor no map, utilizamos a chave correspondente. Por exemplo, ao fornecer a chave joao, o map retorna o valor associado, que é joao@gmail.com.

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // código comentado

  Map<String, String> pessoasEmails = {
    'joao': 'joao@gmail.com',
    'maria': 'maria@gmail.com',
  };

  print(pessoasEmails['joao']);
}

Adicionando Valores ao Map

Podemos adicionar um novo par ao map usando a sintaxe de colchetes. Por exemplo, para associar o e-mail de Enzo ao seu nome, utilizamos pessoasEmails['enzo'] = 'enzo@gmail.com';. Em seguida, podemos imprimir pessoasEmails['enzo'] para obter o e-mail associado:

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // código comentado

  Map<String, String> pessoasEmails = {
    'joao': 'joao@gmail.com',
    'maria': 'maria@gmail.com',
  };

  pessoasEmails['enzo'] = 'enzo@gmail.com';

  print(pessoasEmails['enzo']);
}

Verificando a Existência de Chaves

Outra funcionalidade útil do map é verificar se uma chave existe, utilizando o método containsKey. Isso é especialmente útil para evitar substituições acidentais de valores. Por exemplo, ao utilizar print(pessoasEmails.containsKey('enzo')), obteremos true, indicando que a chave existe.

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // código comentado

  Map<String, String> pessoasEmails = {
    'joao': 'joao@gmail.com',
    'maria': 'maria@gmail.com',
  };

  pessoasEmails['enzo'] = 'enzo@gmail.com';

  print(pessoasEmails.containsKey('enzo'));
}

Se fizéssemos o mesmo utilizando a chave mikael, obteríamos false, pois essa chave não existe no map.

Enviando Mensagens e Visualizando Chaves

Para finalizar, vamos enviar uma mensagem para cada e-mail presente no nosso mapa. Mas, antes de fazer isso, é importante observar que não podemos utilizar o mesmo laço for tradicional que usávamos para listas e sets. Isso acontece porque o pessoasEmails não armazena apenas strings, mas sim pares de chave e valor. Portanto, não podemos usar a mesma abordagem que usamos anteriormente.

A solução é utilizar um método específico para mapas, o values, que nos permite acessar os valores armazenados no mapa. Por exemplo, se quisermos obter apenas os e-mails, podemos usar o comando de impressão print aplicado à pessoasEmails.values:

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // código comentado

  Map<String, String> pessoasEmails = {
    'joao': 'joao@gmail.com',
    'maria': 'maria@gmail.com',
  };

  print(pessoasEmails.values);
}

Ao executar o código, veremos que ele retorna os e-mails associados às chaves, como o e-mail de João e o e-mail de Maria.

Agora, em vez de simplesmente mostrar esses valores, podemos usar um laço for para exibir um e-mail de cada vez, o que torna a visualização mais legível. O código ficaria assim:

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // código comentado

  Map<String, String> pessoasEmails = {
    'joao': 'joao@gmail.com',
    'maria': 'maria@gmail.com',
  };

  for (String email in pessoasEmails.values) {
    print(email);
  }
}

Agora, ao executar o código, veremos o e-mail de João e de Maria. Porém, como o objetivo é enviar uma mensagem para esses e-mails, podemos substituir o print pela nossa função enviarEmail. O código ficaria assim:

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // código comentado

  Map<String, String> pessoasEmails = {
    'joao': 'joao@gmail.com',
    'maria': 'maria@gmail.com',
  };

  for (String email in pessoasEmails.values) {
    enviarEmail(email);
  }
}

Ao rodar o código, veremos as mensagens sendo enviadas para João e Maria, conforme esperado.

mensagem enviada para: joao@gmail.com

mensagem enviada para: maria@gmail.com

Agora, para garantir que o Enzo também receba a mensagem, podemos adicionar o e-mail dele ao mapa utilizando o comando pessoasEmails['enzo'] = 'enzo@gmail.com':

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // código comentado

  Map<String, String> pessoasEmails = {
    'joao': 'joao@gmail.com',
    'maria': 'maria@gmail.com',
  };

  pessoasEmails['enzo'] = 'enzo@gmail.com';

  for (String email in pessoasEmails.values) {
    enviarEmail(email);
  }
}

Após executar o código novamente, teremos a mensagem enviada também para o Enzo.

mensagem enviada para: joao@gmail.com

mensagem enviada para: maria@gmail.com

mensagem enviada para: enzo@gmail.

Além disso, talvez tenhamos curiosidade de saber quais são as chaves do mapa — ou seja, os nomes das pessoas. Para isso, em vez de usar values, podemos usar o método keys. Ao invés de iterar por email, vamos iterar por nome:

void enviarEmail(String email) {
  print('mensagem enviada para: $email');
}

void main() {
  // código comentado

  Map<String, String> pessoasEmails = {
    'joao': 'joao@gmail.com',
    'maria': 'maria@gmail.com',
  };

  pessoasEmails['enzo'] = 'enzo@gmail.com';

  for (String nome in pessoasEmails.keys) {
    print(nome);
  }
}

Agora, ao executar o código, veremos os nomes das pessoas presentes no mapa: João, Maria e Enzo.

Considerações Finais

Com isso, finalizamos o nosso aprendizado sobre mapas e collections. Neste curso, exploramos o funcionamento das listas e seus métodos, as vantagens dos sets e os casos de uso dos maps. Além disso, aprendemos os métodos de cada uma dessas estruturas.

Agora é sua vez! A próxima sessão contém atividades que você pode resolver e compartilhar no fórum. Sinta-se à vontade para compartilhar sua solução ou tirar dúvidas, e eu estarei disponível para responder a cada um de vocês.

Ao final do curso, você verá uma tela de avaliação, e ficarei feliz em receber o seu feedback sobre o que acertamos e o que podemos melhorar.

Muito obrigado e até a próxima!

Sobre o curso Praticando Collections no Dart: listas, sets e mapas

O curso Praticando Collections no Dart: listas, sets e mapas possui 30 minutos de vídeos, em um total de 14 atividades. Gostou? Conheça nossos outros cursos de Flutter em Mobile, ou leia nossos artigos de Mobile.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Flutter acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas