{"id":231705,"date":"2023-01-13T20:27:00","date_gmt":"2023-01-13T17:27:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=231705"},"modified":"2022-12-25T18:46:52","modified_gmt":"2022-12-25T15:46:52","slug":"jak-stworzyc-dwukierunkowa-mape-w-javascript","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pl\/jak-stworzyc-dwukierunkowa-mape-w-javascript\/","title":{"rendered":"Jak stworzy\u0107 dwukierunkow\u0105 map\u0119 w JavaScript"},"content":{"rendered":"\n<p>Mapa dwukierunkowa to model z informatyki, w kt\u00f3rym pary klucz-warto\u015b\u0107 maj\u0105 relacj\u0119 bijective 1-1 mi\u0119dzy kluczami a warto\u015bciami. Pozwala nam to nie tylko na zapytanie wed\u0142ug klucza i uzyskanie warto\u015bci, ale tak\u017ce na zapytanie wed\u0142ug warto\u015bci i uzyskanie klucza. Zobaczmy, jak zaimplementowa\u0107 map\u0119 dwukierunkow\u0105 w JavaScript i zr\u00f3bmy j\u0105 p\u00f3\u017aniej bezpieczn\u0105 w TypeScript<\/p>\n<h2>Informatyka i matematyka za<\/h2>\n<p>Chwy\u0107my podstawow\u0105 definicj\u0119 mapy dwukierunkowej:<\/p>\n<blockquote>\n<p>W informatyce <strong>mapa dwukierunkowa<\/strong> to asocjacyjna struktura danych, w kt\u00f3rej pary klucz-warto\u015b\u0107 tworz\u0105 korespondencj\u0119 jeden do jednego. Zatem relacja binarna dzia\u0142a w ka\u017cdym kierunku: ka\u017cda warto\u015b\u0107 mo\u017ce by\u0107 r\u00f3wnie\u017c odwzorowana na unikalny klucz.<\/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=\"Jak stworzy\u0107 dwukierunkow\u0105 map\u0119 w JavaScript\" ><\/a><\/p>\n<p>\u0179r\u00f3d\u0142o: <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bidirectional_map\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Mapa dwukierunkowa<\/a><\/p>\n<p>Dwukierunkowa mapa z informatyki ma swoje korzenie w funkcji matematycznej zwanej bijekcj\u0105. Relacja mi\u0119dzy sk\u0142adnikami pary z ka\u017cdym z jej sk\u0142adnik\u00f3w w r\u00f3\u017cnych zestawach jest funkcj\u0105 bijektywn\u0105, zwan\u0105 tak\u017ce funkcj\u0105 odwracaln\u0105, kt\u00f3ra jest funkcj\u0105 dzia\u0142aj\u0105c\u0105 w obie strony, paruj\u0105c\u0105 dok\u0142adnie jeden element z jednego zestawu z dok\u0142adnie jednym elementem drugi zestaw:<\/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=\"Jak stworzy\u0107 dwukierunkow\u0105 map\u0119 w JavaScript\" ><\/a><\/p>\n<p>\u0179r\u00f3d\u0142o: <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bijection\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Bijection<\/a><\/p>\n<p>Maj\u0105c to na uwadze, mo\u017cemy wiedzie\u0107, \u017ce funkcja bijektywna dla powy\u017cszych zbior\u00f3w wytworzy co\u015b takiego:<\/p>\n<p>f (1) = D<br \/>\nf (C) = 3<\/p>\n<p>Inn\u0105 rzecz\u0105, kt\u00f3ra wynika z funkcji bijektywnej, jest to, \u017ce zbiory b\u0119d\u0105 mia\u0142y dok\u0142adnie tak\u0105 sam\u0105 d\u0142ugo\u015b\u0107, w przeciwnym razie bijekcja si\u0119 nie powiedzie.<\/p>\n<h2>Zainicjuj map\u0119 dwukierunkow\u0105<\/h2>\n<p>Zamodelujemy to za pomoc\u0105 klasy <a href=\"https:\/\/startfunction.com\/category\/javascript\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">JavaScript<\/a>, kt\u00f3ra zostanie zainicjowana obiektem par klucz-warto\u015b\u0107:<\/p>\n<pre><code>const bimap = new BidirectionalMap({\n  a: 'A',\n  b: 'B',\n  c: 'C',\n})<\/code><\/pre>\n<p>Wewn\u0119trznie utworzymy dwie listy. Jedna lista b\u0119dzie przechowywa\u0107 list\u0119 par tego, co nazwiemy map\u0105 do przodu, gdzie klucz mapuje warto\u015b\u0107 i b\u0119dzie kopi\u0105 obiektu, kt\u00f3rego u\u017cyli\u015bmy do zainicjowania mapy dwukierunkowej. Druga lista b\u0119dzie tym, co nazwiemy map\u0105 odwrotn\u0105 i b\u0119dzie przechowywa\u0107 wersj\u0119 obiektu u\u017cytego do zainicjowania mapy dwukierunkowej, w kt\u00f3rej pary klucz-warto\u015b\u0107 zosta\u0142y odwr\u00f3cone, a \u201ewarto\u015b\u0107&quot; jest teraz mapowana na \u201eklucz&#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>Zwr\u00f3\u0107 uwag\u0119, \u017ce ze wzgl\u0119du na natur\u0119 obiektu, kt\u00f3ry inicjuje map\u0119 dwukierunkow\u0105, nie mo\u017cesz u\u017cy\u0107 liczby jako klucza, ale nadal mo\u017cesz u\u017cy\u0107 jej jako warto\u015bci, a p\u00f3\u017aniej b\u0119dziesz m\u00f3g\u0142 wykonywa\u0107 zapytania wed\u0142ug niej:<\/p>\n<pre><code>const bimap = new BidirectionalMap({\n  a: 42,\n  b: 'B',\n  c: 'C',\n})<\/code><\/pre>\n<p>Bardziej niezawodn\u0105, \u200b\u200bcho\u0107 r\u00f3wnie\u017c bardziej z\u0142o\u017con\u0105 wersj\u0119 mo\u017cna napisa\u0107 z <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Map\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">typem danych Map<\/a> JavaScript i zezwala\u0107 na klucze, kt\u00f3re s\u0105 liczbami, funkcjami, a nawet NaN.<\/p>\n<h2>Pobierz element z mapy dwukierunkowej<\/h2>\n<p>Do tego momentu mamy struktur\u0119 danych, kt\u00f3ra obs\u0142uguje dwa obiekty, z kt\u00f3rych jeden jest odzwierciedleniem drugiego pod wzgl\u0119dem klucza \u2013 warto\u015bci. Potrzebujemy teraz metody, aby co\u015b z tego wyci\u0105gn\u0105\u0107. Zaimplementujmy <code>get()<\/code>funkcj\u0119:<\/p>\n<pre><code>  get( key) {\n      return this.fwdMap[key] || this.revMap[key]\n  }<\/code><\/pre>\n<p>To bardzo proste: je\u015bli istnieje w mapie do przodu, zwracamy go, w przeciwnym razie zwracamy go z mapy odwr\u00f3conej. Je\u015bli nie istnieje, <code>undefined<\/code>zostanie zwr\u00f3cony.<\/p>\n<p>Mo\u017cemy teraz uzyska\u0107 kilka element\u00f3w takich jak:<\/p>\n<pre><code>console.log( bimap.get('a')) console.log( bimap.get('A')) <\/code><\/pre>\n<h2>Dodaj element do mapy dwukierunkowej<\/h2>\n<p>Nasza mapa nie ma obecnie mo\u017cliwo\u015bci dodawania kolejnych element\u00f3w, wi\u0119c dodajmy funkcj\u0119 dodawania nowych element\u00f3w do mapy:<\/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>Spowoduje to otrzymanie tablicy dw\u00f3ch element\u00f3w, kt\u00f3re p\u00f3\u017aniej wpiszemy jako krotk\u0119 za pomoc\u0105 <a href=\"https:\/\/startfunction.com\/tag\/typescript\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">TypeScript<\/a> i przypiszemy je jako klucz \u2013 warto\u015bci w obu kierunkach do odpowiednich obiekt\u00f3w.<\/p>\n<p>A teraz mo\u017cemy doda\u0107 par\u0119 i zapyta\u0107 o t\u0119 now\u0105 par\u0119<\/p>\n<pre><code>bimap.add(['d', 'D'])\nconsole.log( bimap.get('D')) <\/code><\/pre>\n<h2>Bezpieczna dwukierunkowa mapa typu w TypeScript<\/h2>\n<p>Aby by\u0142o lepiej i bezpieczniej pisa\u0107, mo\u017cemy przepisa\u0107 to w TypeScript i doda\u0107 koncepcje typowania, takie jak obiekt generyczny podczas inicjowania mapy i <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/basic-types.html#tuple\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">krotk\u0119<\/a> podczas dodawania nowego elementu.<\/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>To pisanie sprawia, \u017ce \u200b\u200bnasza mapa jest teraz ca\u0142kowicie bezpieczna i zapewnia, \u017ce \u200b\u200bw tym przypadku zawsze b\u0119dziemy u\u017cywa\u0107 ci\u0105g\u00f3w zar\u00f3wno dla kluczy, jak i warto\u015bci.<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">\u0179r\u00f3d\u0142o nagrywania:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/startfunction.com\" class=\"external external_icon\">startfunction.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mo\u017cesz zapyta\u0107 o te mapy wed\u0142ug klucza i uzyska\u0107 jego warto\u015b\u0107 lub wed\u0142ug warto\u015bci i uzyska\u0107 jego klucz<\/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":[721,732,897,752,845],"tags":[1169],"class_list":["post-231705","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-deweloper","category-javascript-7","category-kod","category-otwarte-zrodlo","category-samouczki","tag-affiai-pl"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/231705","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/comments?post=231705"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/231705\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media\/224548"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media?parent=231705"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/categories?post=231705"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/tags?post=231705"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}