{"id":1013,"date":"2025-05-05T00:00:00","date_gmt":"2025-05-04T23:00:00","guid":{"rendered":"https:\/\/jorgeturiel.es\/?p=1013"},"modified":"2025-06-05T11:28:30","modified_gmt":"2025-06-05T10:28:30","slug":"mapas-o-listas-tipo-clave-valor","status":"publish","type":"post","link":"https:\/\/jorgeturiel.es\/?p=1013","title":{"rendered":"Mapas o listas tipo clave\/valor"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Los mapas  o diccionarios en programaci\u00f3n son listas de datos, que se relacionan con el par clave\/valor. Esto es que cada valor tiene una clave, algo as\u00ed como un diccionario. Que da entrada o clave tiene una descripci\u00f3n o valor.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Este tipo listas se pueden implementar en Free Pascal o Moderm Pascal (ahora este nuevo nombre se est\u00e1 poniendo de moda) usando la clase <em>TFPGMap<\/em>, La clase <em>TFPGMap<\/em> es una especializaci\u00f3n de las clases gen\u00e9ricas.  <\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Introducci\u00f3n<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">La programaci\u00f3n gen\u00e9rica  centra en el algoritmo, y no en el tipo de datos, para ello usa  tios de datos gen\u00e9ricos. Una buena introducci\u00f3n a la programaci\u00f3n con datos gen\u00e9ricos podr\u00eda ser esta:<\/p>\n\n\n\n<figure class=\"wp-block-pullquote\"><blockquote><p>Los gen\u00e9ricos, a veces llamados par\u00e1metros gen\u00e9ricos, un nombre que permite presentarlos mucho mejor. A diferencia del par\u00e1metro de una funci\u00f3n (argumento), que tiene un valor, el par\u00e1metro gen\u00e9rico es un tipo. Y un par\u00e1metro gen\u00e9rico parametrizado una clase, un interfaz, un record, o, con menor frecuencia, un m\u00e9todo.<\/p><cite><a href=\"https:\/\/ftp-developpez.com\/sjrd\/tutoriels\/delphi-generiques\/delphi-genericos.pdf\">https:\/\/ftp-developpez.com\/sjrd\/tutoriels\/delphi-generiques\/delphi-genericos.pdf<\/a><\/cite><\/blockquote><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Declaraci\u00f3n y uso<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Antes de seguir, hay que tener en cuenta que la implementaci\u00f3n de gen\u00e9ricos en Free Pascal es diferente que en Delphi.  Free Pascal implement\u00f3 el uso de gen\u00e9ricos antes que Delphi, y para mantener la compatibilidad con este, se a\u00f1adi\u00f3 la unidad Generics.Collections. M\u00e1s informaci\u00f3n sobre esto en la <a href=\"https:\/\/wiki.freepascal.org\/TDictionary\">wiki de FreePascal<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La clase <em>TFPGMap<\/em> nos permite crear una lista de pares clave\/valor, tal como coment\u00e9 antes. Y la clave y valor puede ser de cualquier tipo de dato, incluso diferentes entre ellos. Aunque con fines did\u00e1cticos, voy a usar cadenas (<em>string)<\/em>. <\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \" >\/\/Clave tipo string\ntype\n  TKey = string;\n\/\/Valor tipo string;\ntype\n  TData = string;\n\ntype\n  TMiMapa = specialize TFPGMap&lt;TKey, TData&gt;;   <\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">C\u00f3mo se puede ver en este c\u00f3digo, debemos usar la unidad <em>fgl<\/em>, y la declaraci\u00f3n del tipo usamos <em>string<\/em> para la clave y lo mismo para el valor.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Observa el c\u00f3digo siguiente:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">program maps;\n\nuses\n  SysUtils,\n  fgl;\n\ntype\n  TMiMapa = specialize TFPGMap&lt;string, string&gt;;\nvar\n  MiMapa: TMiMapa;   \nbegin\n  MiMapa := TMiMapa.Create; \/\/Crear el objeto\n  MiMapa.AddOrSetData('Nombre', 'Jorge'); \/\/A\u00f1adir clave valor\n  MiMapa.AddOrSetData('Telefono', '123456789');\n  MiMapa.AddOrSetData('Email', 'email@email.com');\n  MiMapa.AddOrSetData('Borrarme', 'Borrado');\n  Writeln('N\u00famero de elementos: ', MiMapa.Count);  \/\/Mostrar cuantos elementos\n  \/\/No te olvides de liberar el mapa\n  FreeAndNil(MiMapa);\nend.<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">En la l\u00ednea 12 creamos el mapa. Tras ello, a\u00f1adimos diferentes pares clave\/valor. En la l\u00ednea 17 mostramos el n\u00famero de elementos que hay, por supuesto, antes de terminar liberamos la memoria.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">B\u00fasqueda de un elemento<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Ahora vamos modificar el c\u00f3digo anterior para localizar una clave y su valor<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \"> \/\/No borres el c\u00f3digo que hay aqu\u00ed\nvar\n  MiMapa: TMiMapa;\n  Valor: string;     \nbegin\n \/\/No borres el c\u00f3digo que hay aqu\u00ed\n  MiMapa.AddOrSetData('Borrarme', 'Borrado'); \n  \/\/inserta esto\n  Writeln('N\u00famero de elementos: ', MiMapa.Count);\n  if MiMapa.TryGetData('Telefono', Valor) then\n  begin\n    Writeln('Encontr\u00f3 tel\u00e9fono', Valor);\n  end;\n  Writeln('N\u00famero de elementos: ', MiMapa.Count);\n\n  \/\/No te olvides de liberar el mapa\n  FreeAndNil(MiMapa);\nend.<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Con el m\u00e9todo <em>TryGetData<\/em> podemos obtener el valor de una clave. En este caso buscamos la clave <em>Telefono<\/em>. La funci\u00f3n devuelve <em>true<\/em> si encontr\u00f3 la clave indicada. Por el par\u00e1metro <em>Valor<\/em>, nos devuelve el valor que corresponde con la clave buscada.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tambi\u00e9n existe la posibilidad de buscar una clave y obtener el \u00edndice esta. El c\u00f3digo siguiente lo har\u00eda.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">\/\/La lista debe estar ordenada si queremos obtener el indice\n  MiMapa.Sorted := True;\n  Writeln('Buscar el indice de nombre');\n  if MiMapa.Find('Nombre', Indice) = True then\n  begin\n    WriteLn('Encontrado en ', indice);\n    WriteLn(MiMapa.Keys[Indice]);  \/\/Devuelve la clave\n    Writeln(MiMapa.Data[Indice]); \/\/Devuelve el valor\n  end\n  else\n  begin\n    Writeln('No existe');\n  end;                           <\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00edjate que para usar la b\u00fasqueda y obtener el \u00edndice, la lista debe estar ordenada. La m\u00e9todo <em>Find<\/em>, nos devuelve <em>true<\/em> si ha tenido \u00e9xito en la b\u00fasqueda. Y usando los m\u00e9todos <em>Keys<\/em> y <em>Data<\/em>, indic\u00e1ndoles el \u00edndice, podemos obtener la clave y el valor de dicha clave respectivamente.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Probando algunas maldades<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Observa el siguiente c\u00f3digo<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">begin\n  MiMapa := TMiMapa.Create;\n \/\/ MiMapa.OnKeyCompare := @Comparar;\n  MiMapa.AddOrSetData('Nombre', 'Jorge');\n  MiMapa.AddOrSetData('Telefono', '123456789');\n  MiMapa.AddOrSetData('Email', 'email@email.com');\n  MiMapa.AddOrSetData('Borrarme', 'Borrado');\n  Writeln('N\u00famero de elementos: ', MiMapa.Count);\n  if MiMapa.TryGetData('Telefono', Valor) then\n  begin\n    Writeln('Encontr\u00f3 tel\u00e9fono', Valor);\n  end;\n  \/\/La lista debe estar ordenada si queremos obtener el indice\n  MiMapa.Sorted := True;\n  Writeln('Buscar el indice de nombre');\n  if MiMapa.Find('Nombre', Indice) = True then\n  begin\n    WriteLn('Encontrado en ', indice);\n    WriteLn(MiMapa.Keys[Indice]);  \/\/Devuelve la clave\n    Writeln(MiMapa.Data[Indice]); \/\/Devuelve el valor\n  end\n  else\n  begin\n    Writeln('No existe');\n  end;\n  Writeln('A\u00f1adimos un repetido');\n  MiMapa.AddOrSetData('Email', 'email@email.com');\n  \/\/Como es repetido no lo a\u00f1ade\n  Writeln('N\u00famero de elementos: ', MiMapa.Count);\n  \/\/Substituye el valor de la clave\n  MiMapa.AddOrSetData('Email', 'email1@email.com');\n  WriteLn(MiMapa.KeyData['Email']);\n  \/\/Borrar un elemento.\n  MiMapa.Remove('Borrarme');\n  \/\/hay uno menos\n  Writeln('N\u00famero de elementos: ', MiMapa.Count);\n  MiMapa.Remove('Borrarme');\n  \/\/Sino existe no pasa nada.\n  Writeln('N\u00famero de elementos: ', MiMapa.Count);\n\n  \/\/No te olvides de liberar el mapa\n  FreeAndNil(MiMapa);  <\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">En este c\u00f3digo, realizamos algunas \u00abmaldades\u00bb, como a\u00f1adir una clave y valor que ya existe (l\u00ednea 27). Al hacer esto no ocurre ning\u00fan error ni aviso, etc. Simplemente no se a\u00f1ade. Esto se comprueba que el n\u00famero de elementos no ha variado<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En el caso de que la clave exista, y el valor se diferente (l\u00ednea 31) se modifica el contenido del valor. Tal como se muestra en la l\u00ednea siguiente.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para borrar un elemento, simplemente llamando al m\u00e9todo <em>Remove<\/em>, indicando su clave, este es eliminado (l\u00ednea 34). Si tratamos de borrar una clave que no existe, simplemente no ocurre nada, tal como muestra la l\u00ednea 37.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Gestionar el orden.<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">En este ejemplo, simplemente, hemos a\u00f1adido y borrado elementos. Pero tambi\u00e9n tenemos la posibilidad de gestionar el orden de los elementos que se a\u00f1aden. Esto es interesante, sobre todo, cuando la clave, o el valor es un tipo de dato como un objeto. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La clase <em>TMap<\/em>, dispone de dos eventos, los cuales podemos usar en nuestro programa. Estos <em>OnDataCompare<\/em> y <em>OnKeyCompare<\/em>. Estos eventos se dispara cada vez que hay que comparar se compara un valor, o una clave. Para hacer uso de alguna de estos eventos, debemos asignarlo en el momento de crear el objeto.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \" >  MiMapa.OnKeyCompare := @Compararkeys;\n  MiMapa.OnDataCompare := @CompararValores;  <\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Y declarar las correspondientes funciones.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \" >  function Compararkeys(const Key1, Key2: TKey): integer;\n  begin\n      Result := CompareStr(Key1,Key2);\n  end;\n\n  function CompararValores(const Data1, Data2: TData): integer;\n  begin\n     Result := CompareStr(Data1,Data2);\n  end;                          <\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">El valor que deben devolver es un entero cuyo valor debe ser uno de los siguientes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Si el resultado de esta funci\u00f3n es negativo, se considera que la primera clave (key1) es &#8216;menor&#8217; que la segunda clave (key2) y se mover\u00e1 antes que la segunda en la lista.<\/li>\n\n\n\n<li>Si el resultado de la funci\u00f3n es positivo, se considera que la primera clave (key1) es &#8216;mayor que&#8217; la segunda clave (key2) y se mover\u00e1 despu\u00e9s de la segunda en la lista.<\/li>\n\n\n\n<li>Si el resultado de la funci\u00f3n es cero, se considera que las claves son &#8216;iguales&#8217; y no se realizar\u00e1 ning\u00fan movimiento.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Te dejo aqu\u00ed abajo el c\u00f3digo completo. \u00c9chale un vistazo.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \" >program maps;\n\nuses\n  SysUtils,\n  fgl;\n\ntype\n  TKey = string;\ntype\n  TData = string;\n\ntype\n  TMiMapa = specialize TFPGMap&lt;TKey, TData&gt;;\n\nvar\n  MiMapa: TMiMapa;\n  Indice: integer;\n  Valor: string;\n\n\n  function Compararkeys(const Key1, Key2: TKey): integer;\n  begin\n      Result := CompareStr(Key1,Key2);\n  end;\n\n  function CompararValores(const Data1, Data2: TData): integer;\n  begin\n     Result := CompareStr(Data1,Data2);\n  end;\n\nbegin\n  MiMapa := TMiMapa.Create;\n  MiMapa.OnKeyCompare := @Compararkeys;\n  MiMapa.OnDataCompare := @CompararValores;\n  MiMapa.AddOrSetData('Nombre', 'Jorge');\n  MiMapa.AddOrSetData('Telefono', '123456789');\n  MiMapa.AddOrSetData('Email', 'email@email.com');\n  MiMapa.AddOrSetData('Borrarme', 'Borrado');\n  Writeln('N\u00famero de elementos: ', MiMapa.Count);\n  if MiMapa.TryGetData('Telefono', Valor) then\n  begin\n    Writeln('Encontr\u00f3 tel\u00e9fono', Valor);\n  end;\n  \/\/La lista debe estar ordenada si queremos obtener el indice\n  MiMapa.Sorted := True;\n  Writeln('Buscar el indice de nombre');\n  if MiMapa.Find('Nombre', Indice) = True then\n  begin\n    WriteLn('Encontrado en ', indice);\n    WriteLn(MiMapa.Keys[Indice]);  \/\/Devuelve la clave\n    Writeln(MiMapa.Data[Indice]); \/\/Devuelve el valor\n  end\n  else\n  begin\n    Writeln('No existe');\n  end;\n  Writeln('A\u00f1adimos un repetido');\n  MiMapa.AddOrSetData('Email', 'email@email.com');\n  \/\/Como es repetido no lo a\u00f1ade\n  Writeln('N\u00famero de elementos: ', MiMapa.Count);\n  \/\/Substituye el valor de la clave\n  MiMapa.AddOrSetData('Email', 'email1@email.com');\n  WriteLn(MiMapa.KeyData['Email']);\n  \/\/Borrar un elemento.\n  MiMapa.Remove('Borrarme');\n  \/\/hay uno menos\n  Writeln('N\u00famero de elementos: ', MiMapa.Count);\n  MiMapa.Remove('Borrarme');\n  \/\/Sino existe no pasa nada.\n  Writeln('N\u00famero de elementos: ', MiMapa.Count);\n\n  \/\/No te olvides de liberar el mapa\n  FreeAndNil(MiMapa);\nend.<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Saludos<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Los mapas o diccionarios en programaci\u00f3n son listas de datos, que se relacionan con el par clave\/valor. Esto es que cada valor tiene una clave, algo as\u00ed como un diccionario. Que da entrada o clave tiene una descripci\u00f3n o valor. Este tipo listas se pueden implementar en Free Pascal o Moderm Pascal (ahora este nuevo [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":1032,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[61,27,25,26],"tags":[64,32,23],"class_list":["post-1013","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-free-pascal","category-lazarus","category-pascal","category-programacion","tag-ejercicio-programacion","tag-free-pascal","tag-lazarus"],"_links":{"self":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/1013","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1013"}],"version-history":[{"count":19,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/1013\/revisions"}],"predecessor-version":[{"id":1035,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/1013\/revisions\/1035"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/media\/1032"}],"wp:attachment":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1013"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1013"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1013"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}