DEV Community

Diego Novais
Diego Novais

Posted on • Edited on

O que é um map?

Em outras linguagens de programação, como Ruby, conhecemos a estrutura de dados abaixo como Hash, em JavaScript a mesma estrutura de dados é chamada de objeto, já em python é chamada de dicionário.

data = {name: "Diego", last_name: "Novais", age: 33}
data.class
> Hash
Enter fullscreen mode Exit fullscreen mode

Em Elixir nós chamamos de Map e a forma como codificamos é um pouco diferente:

Utilizando %{...} e dentro dessa estrutura é adicionado pares de chave e valor key => value.

data = %{"name" => "Diego", :last_name => "Novais", 33 => "age"}
Enter fullscreen mode Exit fullscreen mode

Aprofundando um pouco mais...

Em Elixir, Map é implementado em hash tree (árvores de hash), diferente de outras linguagens que é implementado usando hash table (tabela de hash).

Pode ser que em alguma tecnologia que você use também seja em hash tree, ou até mesmo de outra forma e eu adoraria saber, fique a vontade para dizer nos comentários =D.

Map foi implementado com hash tree por ser mais eficiente em relação à memória em linguagens funcionais com estruturas de dados imutáveis.

Dessa forma uma pesquisa por chave passa a ter um desempenho O(log (n)).

O desempenho de O(log (n)), sendo logarítmico, ainda é muito bom, e é apenas um pouco pior do que O(1), mesmo quando a quantidade de dados é enorme. Dê uma olhada no cheatsheet do Big O para obter uma boa visualização das diferenças relativas.

-- https://inquisitivedeveloper.com/lwm-elixir-47/


É importante saber que...

  • As Chaves e valores em um Map, não seguem a ordem em que codificamos.
iex> data = %{"name" => "Diego", :last_name => "Novais", 33 => "age"}
%{33 => "age", :last_name => "Novais", "name" => "Diego"}
Enter fullscreen mode Exit fullscreen mode
  • Os Maps não impõem nenhuma restrição ao tipo de chave, qualquer coisa pode ser uma chave em um mapa.
%{"string" => "Value", :atom => "Other value", 33 => "A integer"}
Enter fullscreen mode Exit fullscreen mode
  • Como uma estrutura de chave-valor, os Maps não permitem chaves duplicadas. As chaves são comparadas usando o operador de igualdade exata (=== / 2).

  • Quando a chave em um par de key-value é um :atom, a sintaxe abreviada (shorthand syntax) key: value pode ser usada:

%{name: "Diego", last_name: "Novais", age: 33}
Enter fullscreen mode Exit fullscreen mode
  • Os itens no Map podem ser acessados:
    • Funções do módulo Map: Map.get/3 ou Map.fetch/2.
 iex> data = %{name: "Diego", last_name: "Novais", age: 33}
 %{name: "Diego", last_name: "Novais", age: 33}

 # Usando o Map.fetch/2
 iex> Map.fetch(data, :name)
 {:ok, "Diego"}

 # Usando o Map.get/3
 iex> Map.get(data, :name)
 "Diego"

 iex> Map.get(data, :year, 1987)
 1987
Enter fullscreen mode Exit fullscreen mode
 iex> data = %{name: "Diego", last_name: "Novais", age: 33}
 %{name: "Diego", last_name: "Novais", age: 33}

 iex> data[:name]
 "Diego"
Enter fullscreen mode Exit fullscreen mode
  • Quando a chave for um :atom, o elemento pode ser acessado através da notação map.key
 iex> data = %{name: "Diego", last_name: "Novais", age: 33}
 %{name: "Diego", last_name: "Novais", age: 33}

 iex> data.name
 "Diego"
Enter fullscreen mode Exit fullscreen mode

Obs.: não adicione parênteses ao acessar campos data.key(). Pois o Elixir irá considerar como uma chamada de função nos dados.

  • Caso precise, por exemplo, manipular, pesquisar, deletar o Map e/ou algum de seus elementos, o próprio módulo Map possui várias funções que podem ser úteis, e você pode consultar na documentação do Elixir que é bastante completa, por isso não irei entrar em cada função neste primeiro artigo sobre Map.

Caso fique alguma dúvida, pode entrar em contato que irei te ajudar.

Conclusão

Um Map é análogo ao hash em ruby, ao objeto em JS e ao dicionário em python (apenas uma referência à linguagens de programação que eu conheço, e reforçando, pode ser que você tenha outra(s) referência(s) e eu adoraria saber, fique a vontade para dizer nos comentários =D).

No Elixir, temos vários detalhes sobre o Map que precisamos entender e meu objetivo foi trazer os principais pontos de uma forma mais didática possível. Espero que faça sentido para você e te ajude de alguma forma.

Top comments (4)

Collapse
 
eduardoklosowski profile image
Eduardo Klosowski

Achei estranho o Map não ter restrição ao tipo de valor usado como chave, uma vez que o Map é implementado com hash tree, como você disse. Em várias linguagens, para que isso seja possível, o tipo da chave precisa implementar uma função de hash, já que a estrutura depende disso para funcionar. Como isso funciona no Elixir? Se todos os tipos já tiverem uma função de hash por padrão, nesse caso poderia ser qualquer tipo, uma vez que a própria linguagem já garante essa condição.

Collapse
 
dnovais profile image
Diego Novais

Sim, Map não tem restrição ao tipo usado na chave. Mas geralmente é mais comum o uso de string ou atoms na chave.
Pelo que eu pude entender, aprofundando um pouco mais, no Erlang o map era em table hash table, a patir da verão 18 passou a ser implementado o Map usando Hash Tree para eliminar o problema que se tem quando os maps crescem demais.

O Hash Tree é uma estrutura para organizar dados arbitrários em uma árvore amplamente ramificada. É comum seu uso em linguagens funcionais para contrução de mapas de hash imutáveis. Mais complexa do que uma hash table, e oferece alguns benefícios:

  • Capacidade de aumentar o mapa indefinidamente sem redimensionar ou encadear (sem penalidades de re-hash)

  • Capacidade de compartilhar estruturas repetidas entre árvores semelhantes.

E pelo que vi, quando quisermos inserir ou manipular um par de valores-chave, usaremos o código hash da chave para escolher um caminho através do trie até encontrar uma posição. O que permite que sejam estruturas de dados persistentes e com a imutabilidade dos hashs, faz com que não tenha restrição quanto o tipo da chave no map.

Collapse
 
eduardoklosowski profile image
Eduardo Klosowski

Interessante, então é usado de fato o hash. Em algumas linguagens não existe uma implementação padrão da função que gera os hashs, então para usar certos tipos como chave, precisa implementar manualmente a interface para isso (pensando em orientação a objetos). Árvore são bastante interessantes também, inclusive como criá-las ou mantê-las balanceadas, tendo um funcionamento parecido com a busca binária, além de poder usar a própria ordenação pelos seus valores em vez do hash.

Thread Thread
 
dnovais profile image
Diego Novais

Sim árvores são bem interessante mesmo, quero trazer algo sobre isso no futuro também =D.

Interessante esse video! Gostei!

Ah e obrigado! Foi muito bom nossa conversa e até aprendi mais detalhes a respeito dos Maps. =D