{"id":232331,"date":"2023-01-13T20:17:00","date_gmt":"2023-01-13T17:17:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=232331"},"modified":"2022-11-10T08:46:48","modified_gmt":"2022-11-10T05:46:48","slug":"como-criar-um-mapa-bidirecional-em-javascript","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pt-pt\/como-criar-um-mapa-bidirecional-em-javascript\/","title":{"rendered":"Como criar um mapa bidirecional em JavaScript"},"content":{"rendered":"\n<p>Um mapa bidirecional \u00e9 um modelo da ci\u00eancia da computa\u00e7\u00e3o em que os pares chave-valor t\u00eam uma rela\u00e7\u00e3o bijetiva 1-1 entre as chaves e os valores. Isso nos permite n\u00e3o apenas consultar por chave e obter um valor, mas tamb\u00e9m consultar pelo valor e obter a chave. Vamos ver como implementar um mapa bidirecional em JavaScript e vamos torn\u00e1-lo mais tarde seguro no TypeScript<\/p>\n<h2>A ci\u00eancia da computa\u00e7\u00e3o e a matem\u00e1tica por tr\u00e1s<\/h2>\n<p>Vamos pegar uma defini\u00e7\u00e3o b\u00e1sica de um mapa bidirecional:<\/p>\n<blockquote>\n<p>Na ci\u00eancia da computa\u00e7\u00e3o, um <strong>mapa bidirecional<\/strong> \u00e9 uma estrutura de dados associativa na qual os pares chave-valor formam uma correspond\u00eancia um-para-um. Assim, a rela\u00e7\u00e3o bin\u00e1ria \u00e9 funcional em cada dire\u00e7\u00e3o: cada valor tamb\u00e9m pode ser mapeado para uma chave \u00fanica.<\/p>\n<\/blockquote>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-157501-61e6b9e14822e.png\" data-rel=\"lightbox\" ><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-157501-61e6b9e14822e.png\" alt=\"Como criar um mapa bidirecional em JavaScript\" ><\/a><\/p>\n<p>Cr\u00e9dito: <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bidirectional_map\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Mapa Bidirecional<\/a><\/p>\n<p>O mapa bidirecional da ci\u00eancia da computa\u00e7\u00e3o tem suas ra\u00edzes em uma fun\u00e7\u00e3o matem\u00e1tica chamada bije\u00e7\u00e3o. A rela\u00e7\u00e3o entre os componentes de um par com cada um de seus componentes em conjuntos diferentes \u00e9 uma fun\u00e7\u00e3o bijetiva, tamb\u00e9m chamada de fun\u00e7\u00e3o invert\u00edvel, que \u00e9 uma fun\u00e7\u00e3o que funciona nos dois sentidos, emparelhando exatamente um elemento de um conjunto com exatamente um elemento de o outro conjunto:<\/p>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-157501-61e6b9e2a629e.png\" data-rel=\"lightbox\"><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-157501-61e6b9e2a629e.png\" alt=\"Como criar um mapa bidirecional em JavaScript\" ><\/a><\/p>\n<p>Cr\u00e9dito: <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bijection\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Bije\u00e7\u00e3o<\/a><\/p>\n<p>Com isso em mente, podemos saber que uma fun\u00e7\u00e3o bijetiva para os conjuntos acima produzir\u00e1 algo como:<\/p>\n<p>f (1) = D<br \/>\nf (C) = 3<\/p>\n<p>Outra coisa que surge da fun\u00e7\u00e3o bijetiva \u00e9 que os conjuntos ter\u00e3o exatamente o mesmo comprimento, caso contr\u00e1rio a bije\u00e7\u00e3o falharia.<\/p>\n<h2>Inicialize o mapa bidirecional<\/h2>\n<p>Vamos modelar isso com uma classe <a href=\"https:\/\/startfunction.com\/category\/javascript\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">JavaScript<\/a> que ser\u00e1 inicializada com um objeto de pares chave-valor:<\/p>\n<pre><code>const bimap = new BidirectionalMap({\n  a: 'A',\n  b: 'B',\n  c: 'C',\n})<\/code><\/pre>\n<p>Internamente, criaremos duas listas. Uma lista armazenar\u00e1 a lista de pares do que chamaremos de mapa de encaminhamento, onde a chave mapeia para o valor e ser\u00e1 uma c\u00f3pia do objeto que usamos para inicializar o mapa bidirecional. A segunda lista ser\u00e1 o que chamaremos de mapa reverso e armazenar\u00e1 uma vers\u00e3o do objeto usado para inicializar o mapa bidirecional onde os pares chave-valor foram invertidos e o &#8220;valor&quot; agora mapeia para a &#8220;chave&#8221;:<\/p>\n<pre><code>class BidirectionalMap {\n  fwdMap = {}\n  revMap = {}\n\n  constructor(map) {\n      this.fwdMap = { ...map }\n      this.revMap = Object.keys(map).reduce(\n          (acc, cur) =&gt; ({\n              ...acc,\n              [map[cur]]: cur,\n          }),\n          {}) }\n}<\/code><\/pre>\n<p>Observe que, devido \u00e0 natureza do objeto que inicializa o mapa bidirecional, voc\u00ea n\u00e3o pode usar um n\u00famero para a chave, mas ainda pode us\u00e1-lo como um valor e depois poder\u00e1 consultar por ele:<\/p>\n<pre><code>const bimap = new BidirectionalMap({\n  a: 42,\n  b: 'B',\n  c: 'C',\n})<\/code><\/pre>\n<p>Uma vers\u00e3o mais robusta, embora tamb\u00e9m mais complexa, poderia ser escrita com o <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Map\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">tipo de dados Map<\/a> de JavaScript e permitir chaves que s\u00e3o n\u00fameros, fun\u00e7\u00f5es ou mesmo NaN.<\/p>\n<h2>Obter um elemento de um mapa bidirecional<\/h2>\n<p>At\u00e9 este ponto, temos uma estrutura de dados que hospeda dois objetos, sendo um deles um espelho do outro em termos de valores-chave. Agora precisamos de um m\u00e9todo para tirar algo disso. Vamos implementar uma <code>get()<\/code>fun\u00e7\u00e3o:<\/p>\n<pre><code>  get( key) {\n      return this.fwdMap[key] || this.revMap[key]\n  }<\/code><\/pre>\n<p>\u00c9 muito simples: se existir no mapa direto, n\u00f3s o retornamos, caso contr\u00e1rio, retornamos do mapa invertido. Se n\u00e3o existir, <code>undefined<\/code>ser\u00e1 devolvido.<\/p>\n<p>Agora podemos obter alguns elementos como:<\/p>\n<pre><code>console.log( bimap.get('a')) console.log( bimap.get('A')) <\/code><\/pre>\n<h2>Adicionar um elemento a um mapa bidirecional<\/h2>\n<p>Nosso mapa atualmente n\u00e3o tem como adicionar mais elementos, ent\u00e3o vamos adicionar uma fun\u00e7\u00e3o para adicionar novos elementos ao mapa:<\/p>\n<pre><code>  add( pair) {\n    this.fwdMap[pair[0]] = pair[1]\n    this.revMap[pair[1]] = pair[0]\n  }<\/code><\/pre>\n<p>Isso receber\u00e1 uma matriz de dois elementos, que mais tarde digitaremos como uma tupla com <a href=\"https:\/\/startfunction.com\/tag\/typescript\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">TypeScript<\/a> e os atribuiremos como valores-chave em ambas as dire\u00e7\u00f5es para os objetos correspondentes.<\/p>\n<p>E agora podemos adicionar um par e consultar este novo par<\/p>\n<pre><code>bimap.add(['d', 'D'])\nconsole.log( bimap.get('D')) <\/code><\/pre>\n<h2>Um mapa bidirecional seguro de tipo no TypeScript<\/h2>\n<p>Para tornar as coisas melhores e com seguran\u00e7a de tipos, podemos reescrever isso no TypeScript e adicionar conceitos de digita\u00e7\u00e3o como um objeto gen\u00e9rico ao inicializar o mapa e uma <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/basic-types.html#tuple\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">tupla<\/a> ao adicionar um novo elemento.<\/p>\n<pre><code>class BidirectionalMap {\n  fwdMap = {}\n  revMap = {}\n\n  constructor(map: { [key: string]: string }) {\n      this.fwdMap = { ...map }\n      this.revMap = Object.keys(map).reduce(\n          (acc, cur) =&gt; ({\n              ...acc,\n              [map[cur]]: cur,\n          }),\n          {}) }\n\n  get(key: string): string | undefined {\n      return this.fwdMap[key] || this.revMap[key]\n  }\n\n  add(pair: [string, string]) {\n    this.fwdMap[pair[0]] = pair[1]\n    this.revMap[pair[1]] = pair[0]\n  }\n}<\/code><\/pre>\n<p>Essa digita\u00e7\u00e3o agora torna nosso mapa perfeitamente seguro e garante que, nesse caso, sempre usaremos strings para chaves e valores.<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">Fonte de grava\u00e7\u00e3o:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/startfunction.com\" class=\"external external_icon\">startfunction.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Voc\u00ea pode consultar esses mapas por chave e obter seu valor ou por valor e obter sua chave<\/p>\n","protected":false},"author":1,"featured_media":224548,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[898,753,722,733,846],"tags":[1170],"class_list":["post-232331","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-codigo-2","category-codigo-aberto","category-desenvolvedor","category-javascript-8","category-tutoriais","tag-affiai-pt-pt"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts\/232331","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/comments?post=232331"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts\/232331\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/media\/224548"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/media?parent=232331"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/categories?post=232331"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/tags?post=232331"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}