<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Alejandro Escario | Dipler</title>
	<atom:link href="https://www.dipler.org/author/esc_89/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.dipler.org</link>
	<description></description>
	<lastBuildDate>Fri, 03 Apr 2026 21:57:22 +0000</lastBuildDate>
	<language>es</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Error crítico de Nginx: proxy_cache_key en multidominio</title>
		<link>https://www.dipler.org/2026/04/error-critico-de-nginx-proxy_cache_key-en-multidominio/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=error-critico-de-nginx-proxy_cache_key-en-multidominio</link>
					<comments>https://www.dipler.org/2026/04/error-critico-de-nginx-proxy_cache_key-en-multidominio/#respond</comments>
		
		<dc:creator><![CDATA[Alejandro Escario]]></dc:creator>
		<pubDate>Fri, 03 Apr 2026 21:54:01 +0000</pubDate>
				<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://www.dipler.org/?p=2327</guid>

					<description><![CDATA[<p>Me pasó esta semana. Dos dominios distintos, mismo servidor, misma IP, ambos detrás de Cloudflare. Uno de ellos mostraba el contenido del otro. Así, sin más. Entrabas en el dominio A y veías la web del dominio B. Lo comparto porque es un fallo silencioso, fácil de cometer y difícil<a class="moretag" href="https://www.dipler.org/2026/04/error-critico-de-nginx-proxy_cache_key-en-multidominio/"> Leer más</a></p>
<p>The post <a href="https://www.dipler.org/2026/04/error-critico-de-nginx-proxy_cache_key-en-multidominio/">Error crítico de Nginx: proxy_cache_key en multidominio</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Me pasó esta semana. Dos dominios distintos, mismo servidor, misma IP, ambos detrás de Cloudflare. Uno de ellos mostraba el contenido del otro. Así, sin más. Entrabas en el dominio A y veías la web del dominio B.</p>



<p>Lo comparto porque es un fallo silencioso, fácil de cometer y difícil de diagnosticar si no sabes dónde mirar. Y porque me llevó un rato dar con ello.</p>



<h2 class="wp-block-heading">El montaje</h2>



<p>La arquitectura no tiene nada de raro. Es la que usa medio internet:</p>



<p>Cloudflare por delante como CDN y proxy DNS. Detrás, un servidor con Nginx haciendo de proxy inverso y caché, que pasa las peticiones a un Apache con VirtualHosts separados para cada dominio. Panel tipo cPanel/aaPanel. Nada raro.</p>



<p>Los dos dominios apuntan a la misma IP. Cada uno tiene su VirtualHost en Apache, su directorio, su certificado SSL. Todo como debe ser.</p>



<p>Pero al abrir el dominio A en el navegador, aparecía el contenido del dominio B. Siempre. Da igual si purgabas caché del navegador, si probabas en incógnito, si cambiabas de red. Dominio A = contenido de B.</p>



<h2 class="wp-block-heading">El proceso de descarte</h2>



<p>Lo primero que piensas es que Cloudflare está mezclando respuestas. Dos dominios, misma IP, mismo servidor&#8230; tiene sentido como sospecha inicial. Así que hice Purge Everything en ambos dominios desde el dashboard. Nada, el problema seguía.</p>



<p>Después revisé los VirtualHosts de Apache. Desde el propio servidor lancé:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
curl -H &quot;Host: dominio-a.com&quot; http://localhost:8288
curl -H &quot;Host: dominio-b.com&quot; http://localhost:8288

</pre></div>


<p>Cada curl devolvió el HTML correcto de su dominio. Apache estaba bien. Los VirtualHosts resolvían como tenían que resolver.</p>



<p>SSL/TLS también descartado: ambos dominios con el mismo modo en Cloudflare, certificados correctos en el servidor.</p>



<h2 class="wp-block-heading">La pista falsa del fichero hosts</h2>



<p>Aquí es donde la cosa se pone interesante y donde me despistó.</p>



<p>Si en mi máquina editaba el fichero <code>hosts</code> para apuntar ambos dominios directamente a la IP del servidor —saltándome Cloudflare—, todo funcionaba perfectamente. Cada dominio mostraba su contenido. «Pues es Cloudflare», pensé.</p>



<p>Pero no. La explicación es más sutil.</p>



<p><strong>Cuando te saltas Cloudflare tocando el fichero <code>hosts</code>, cambias las condiciones de la petición. El tráfico real llega a Nginx a través de Cloudflare por HTTPS; las peticiones directas desde tu máquina llegan por HTTP (distinto <code>$scheme</code>). Eso ya cambia la clave de caché internamente, así que Nginx no encuentra una entrada cacheada y consulta a Apache, que responde bien.</strong></p>



<p>Además, cuando pruebas manualmente visitas un dominio, esperas, visitas el otro&#8230; No generas el volumen de tráfico necesario para que el caché se «contamine». En producción, con cientos de peticiones por minuto, el primer dominio que recibe una visita llena el caché y todos los demás se llevan esa misma respuesta.</p>



<p>La moraleja: que algo funcione al saltar un componente de la cadena no significa que ese componente sea el culpable. En este caso Cloudflare no hacía absolutamente nada mal. Solo era la puerta por la que entraba el tráfico real que exponía el bug de Nginx.</p>



<h2 class="wp-block-heading">La causa real: el proxy_cache_key</h2>



<p>Con Apache y Cloudflare descartados, quedaba Nginx. Fui al <code>proxy.conf</code> y ahí estaba:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
proxy_cache_path /www/server/nginx/proxy_cache_dir levels=1:2 
    keys_zone=cache_one:20m inactive=1d max_size=5g;

proxy_cache cache_one;

</pre></div>


<p>Caché activado globalmente. Ningún <code>proxy_cache_key</code> definido.</p>



<p>Cuando no defines un <code>proxy_cache_key</code> explícito, Nginx usa por defecto:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
$scheme$proxy_host$request_uri

</pre></div>


<p>Y aquí está el problema. <code>$proxy_host</code> no es el dominio que pidió el visitante. Es la dirección del <code>proxy_pass</code>, o sea, el backend. Como ambos vhosts de Nginx envían las peticiones a <code>http://127.0.0.1:8282</code>, esa variable vale lo mismo para los dos dominios.</p>



<p>Vamos a verlo con un ejemplo concreto. Un GET a la raíz de cada dominio:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Variable</th><th>dominio-a.com</th><th>dominio-b.com</th></tr></thead><tbody><tr><td><code>$scheme</code></td><td><code>http</code></td><td><code>http</code></td></tr><tr><td><code>$proxy_host</code></td><td><code>127.0.0.1:828</code>2</td><td><code>127.0.0.1:828</code>2</td></tr><tr><td><code>$request_uri</code></td><td><code>/</code></td><td><code>/</code></td></tr><tr><td><strong>Clave resultante</strong></td><td><code>http127.0.0.1:8282/</code></td><td><code>http127.0.0.1:8282/</code></td></tr></tbody></table></figure>



<p>Misma clave. Para Nginx, pedir la home de dominio-a.com o de dominio-b.com es exactamente la misma petición. El primero que llega gana, y el segundo se come su contenido cacheado.</p>



<h2 class="wp-block-heading">La secuencia completa del fallo</h2>



<p>Para que quede claro lo que ocurre en producción:</p>



<ol class="wp-block-list">
<li>Alguien visita dominio-b.com. Nginx no tiene caché para <code>http127.0.0.1:8282/</code>, así que le pregunta a Apache.</li>



<li>Apache devuelve la web de dominio-b.com. Nginx la guarda en caché con esa clave.</li>



<li>Alguien visita dominio-a.com. Nginx calcula la clave: <code>http127.0.0.1:8282/</code>. Ya la tiene.</li>



<li>Nginx devuelve el contenido de dominio-b.com sin consultar a Apache.</li>
</ol>



<p>El dominio que se visite primero después de un reinicio o una limpieza de caché es el que «gana». Los demás quedan secuestrados.</p>



<h2 class="wp-block-heading">La solución</h2>



<p>Una línea. En <code>proxy.conf</code>, después de <code>proxy_cache cache_one;</code>, añades:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
proxy_cache_key &quot;$host$scheme$request_method$request_uri&quot;;

</pre></div>


<p>La diferencia es que ahora la clave incluye <code>$host</code>, que sí es el dominio que pidió el visitante:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Dominio</th><th>Clave de caché</th></tr></thead><tbody><tr><td>dominio-a.com</td><td><code>dominio-a.comhttpsGET/</code></td></tr><tr><td>dominio-b.com</td><td><code>dominio-b.comhttpsGET/</code></td></tr></tbody></table></figure>



<p>Claves distintas. Cada dominio tiene su propio espacio en caché. Fin del problema.</p>



<p>Después de editar:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
# Limpiar el caché existente
rm -rf /www/server/nginx/proxy_cache_dir/*

# Comprobar que la config es válida
nginx -t

# Recargar
nginx -s reload

</pre></div>


<p>Y un Purge Everything en Cloudflare en ambos dominios para eliminar copias cacheadas con la respuesta incorrecta.</p>



<h2 class="wp-block-heading">Lo que aprendí (o reaprendí)</h2>



<p>Llevo años montando servidores y esta me pilló. Es un fallo que no da error en logs, no lanza ningún warning, <code>nginx -t</code> dice que todo está perfecto. Simplemente sirve contenido equivocado en silencio.</p>



<p>Hay varias cosas que ahora hago siempre:</p>



<p>Definir <code>proxy_cache_key</code> de forma explícita en cualquier servidor que aloje más de un dominio. El default de Nginx no incluye <code>$host</code> y eso es una bomba de relojería en entornos multidominio.</p>



<p>Comprobar que <code>proxy_set_header Host $host</code> está en cada bloque <code>location</code> que haga <code>proxy_pass</code>. Sin eso, Apache recibe un host incorrecto y puede devolver el VirtualHost por defecto.</p>



<p>Añadir este header para monitorizar el comportamiento del caché:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
add_header X-Cache-Status $upstream_cache_status;

</pre></div>


<p>Con eso puedes ver si una respuesta fue <code>HIT</code> (caché), <code>MISS</code> (fue al backend) o <code>BYPASS</code>. Si ves un HIT en un dominio que acaba de cambiar de contenido, sabes que tienes un problema de clave.</p>



<p>Y sobre todo: no fiarte de las pruebas con el fichero <code>hosts</code>. Cambian demasiadas variables respecto al tráfico real como para que sean representativas.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><strong>Síntoma</strong></td><td>Varios dominios muestran el contenido de uno solo</td></tr><tr><td><strong>Causa</strong></td><td><code>proxy_cache_key</code> por defecto no incluye <code>$host</code></td></tr><tr><td><strong>Solución</strong></td><td><code>proxy_cache_key "$host$scheme$request_method$request_uri";</code></td></tr><tr><td><strong>Tiempo real de corrección</strong></td><td>2 minutos, una vez identificado</td></tr></tbody></table></figure><p>The post <a href="https://www.dipler.org/2026/04/error-critico-de-nginx-proxy_cache_key-en-multidominio/">Error crítico de Nginx: proxy_cache_key en multidominio</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.dipler.org/2026/04/error-critico-de-nginx-proxy_cache_key-en-multidominio/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Wazuh no muestra información de los equipos de repente</title>
		<link>https://www.dipler.org/2024/02/wazuh-no-muestra-informacion-de-los-equipos-de-repente/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=wazuh-no-muestra-informacion-de-los-equipos-de-repente</link>
					<comments>https://www.dipler.org/2024/02/wazuh-no-muestra-informacion-de-los-equipos-de-repente/#respond</comments>
		
		<dc:creator><![CDATA[Alejandro Escario]]></dc:creator>
		<pubDate>Wed, 31 Jan 2024 22:47:39 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://www.dipler.org/?p=2317</guid>

					<description><![CDATA[<p>Wash es un software SIEM muy potente y versátil. Está basado en el stack ELK para lo bueno y para lo malo. Si bien ELK es un sistema muy potente y robusto, hay que tener en cuenta en todo momento que es un sistema muy sensible a las versiones de<a class="moretag" href="https://www.dipler.org/2024/02/wazuh-no-muestra-informacion-de-los-equipos-de-repente/"> Leer más</a></p>
<p>The post <a href="https://www.dipler.org/2024/02/wazuh-no-muestra-informacion-de-los-equipos-de-repente/">Wazuh no muestra información de los equipos de repente</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Wash es un software SIEM muy potente y versátil. Está basado en el stack ELK para lo bueno y para lo malo. Si bien ELK es un sistema muy potente y robusto, hay que tener en cuenta en todo momento que es un sistema muy sensible a las versiones de sus distintos componentes.</p>



<p>ELK tiene dos grandes repositorios en función de la licencia del mismo como podemos ver en su <a href="https://www.elastic.co/guide/en/beats/filebeat/current/setup-repositories.html" target="_blank" rel="noopener" title="">web</a>. Es de vital importancia que las versiones de los distintos componentes de nuestra arquitectura sean consistentes entre sí y, sin embargo, es muy común que, si no tenemos cuidado al usar los gestores de paquetes para actualizar este software surjan complicaciones. Por ejemplo, la versión 7.10 de ElasticSearch no es compatible con la 7.13+ de la misma distribución o que, por ejemplo la versión 7.10 de ElasticSearch no es compatible con la versión oss-7.10 de filebeat.</p>



<p>y&#8230; ¿Qué tiene que ver todo esto con Wazuh? pues bien, me encuentro en varias ocasiones con situaciones en las que veo que el dashboard deja de mostrar datos de los equipos de repente. </p>



<figure class="wp-block-image size-large"><a href="https://www.dipler.org/wp-content/uploads/2024/02/image.png"><img fetchpriority="high" decoding="async" width="1024" height="544" src="https://www.dipler.org/wp-content/uploads/2024/02/image-1024x544.png" alt="" class="wp-image-2321" srcset="https://www.dipler.org/wp-content/uploads/2024/02/image-1024x544.png 1024w, https://www.dipler.org/wp-content/uploads/2024/02/image-300x159.png 300w, https://www.dipler.org/wp-content/uploads/2024/02/image-768x408.png 768w, https://www.dipler.org/wp-content/uploads/2024/02/image.png 1488w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Ejemplo de dashboard de wazuh.</figcaption></figure>



<p>Cuando el dashboard de Wazuh deja de mostrar datos de repente, lo primero que deberemos hacer es entrar a la consola del equipo y ejecutar el comando: </p>



<pre class="wp-block-code"><code>~# filebeat test output</code></pre>



<p>Este comando revisará la configuración y la comunicación entre los componentes. En mi caso obtuve la siguiente salida:</p>



<pre class="wp-block-code"><code>~# filebeat test output
elasticsearch: https://192.168.1.10:9200...
  parse url... OK
  connection...
    parse host... OK
    dns lookup... OK
    addresses: 192.168.1.10
    dial up... OK
  TLS...
    security: server's certificate chain verification is enabled
    handshake... OK
    TLS version: TLSv1.2
    dial up... OK
  talk to server... ERROR Connection marked as failed because the onConnect callback failed: could not connect to a compatible version of Elasticsearch: 400 Bad Request: {"error":{"root_cause":&#91;{"type":"invalid_index_name_exception","reason":"Invalid index name &#91;_license], must not start with '_'.","index":"_license","index_uuid":"_na_"}],"type":"invalid_index_name_exception","reason":"Invalid index name &#91;_license], must not start with '_'.","index":"_license","index_uuid":"_na_"},"status":400}</code></pre>



<p>Llegados a este punto podemos ver en el mensaje que hay problemas de licencia. Es decir, las versiones por «alguna razón» son incompatibles. En este caso se podía observar como la versión de filebeat era una:</p>



<pre class="wp-block-code"><code>~# filebeat version
filebeat version 7.17.17 (amd64), libbeat 7.17.17 &#91;af0928f86fb2f8c2da6e72ad7eef25d67f7815c9 built 2024-01-17 19:05:41 +0000 UTC]</code></pre>



<p>Mientras que la versión de elastic search era otra:</p>



<pre class="wp-block-code"><code>~# curl -XGET -k https://&lt;ELASTICSEARCH_HOST_IP>:9200 -u &lt;ELASTICSEARCH_USER>:&lt;ELASTICSEARCH_USER_PASSWORD>

{
  "name" : "node-1",
  "cluster_name" : "wazuh-indexer-cluster",
  "cluster_uuid" : "DaJoCkJWSA7mSH2yOgnJZw",
  "version" : {
    "number" : "7.10.2",
    "build_type" : "rpm",
    "build_hash" : "db90a415ff2fd428b4f7b3f800a51dc229287cb4",
    "build_date" : "2023-06-03T06:24:25.112415503Z",
    "build_snapshot" : false,
    "lucene_version" : "9.6.0",
    "minimum_wire_compatibility_version" : "7.10.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "The OpenSearch Project: https://opensearch.org/"
}</code></pre>



<p>Llegados a este punto, todo nos indica que tenemos que bajar la versión de filebeat ya que en la versión 7.13+ se introdujeron cambios importantes.</p>



<pre class="wp-block-code"><code>~# apt  install filebeat=7.10.2</code></pre>



<p>Llegados a este punto pueden pasar dos cosas, que las versiones sean las correctas o que falte algo por hacer. En este caso, al ejecutar el comando de test de nuevo, veremos que, al menos en mi caso salía el siguiente error:</p>



<pre class="wp-block-code"><code>~# filebeat test output
elasticsearch: https://192.168.1.10:9200...
  parse url... OK
  connection...
    parse host... OK
    dns lookup... OK
    addresses: 1.1.1.1
    dial up... OK
  TLS...
    security: server's certificate chain verification is enabled
    handshake... OK
    TLS version: TLSv1.2
    dial up... OK
  talk to server... ERROR Connection marked as failed because the onConnect callback failed: Filebeat requires the default distribution of Elasticsearch. Please update to the default distribution of Elasticsearch for full access to all free features, or switch to the OSS distribution of Filebeat.</code></pre>



<p>Ahora el error es mucho más claro. Tenemos ElasticSearch y Filebeat en la misma versión pero en una distribución distinta. Para solucionar esto vamos a cambiar el origen del repositorio de elasticsearch para que concuerde con el instalado por wazuh:</p>



<pre class="wp-block-code"><code>~# nano /etc/apt/sources.list.d/elastic-7.x.list </code></pre>



<p>Y cambiaremos la línea:</p>



<pre class="wp-block-code"><code>deb https://artifacts.elastic.co/packages/7.x/apt stable main</code></pre>



<p>Por</p>



<pre class="wp-block-code"><code>deb https://artifacts.elastic.co/packages/oss-7.x/apt stable main


Ahora actualizamos la lista de repositorios y volvemos a instalar filebeat en la versión deseada pero esta vez en su distribución OSS:</code></pre>



<pre class="wp-block-code"><code>~# apt update
~# apt  install filebeat=7.10.2</code></pre>



<p>Si ahora ejecutamos el comando de pruebas, veremos como el resultado es correcto:</p>



<pre class="wp-block-code"><code>~# filebeat test output
elasticsearch: https://192.168.1.10:9200…
parse url… OK
connection…
parse host… OK
dns lookup… OK
addresses: 192.168.1.10
dial up… OK
TLS…
security: server's certificate chain verification is enabled
handshake… OK
TLS version: TLSv1.2
dial up… OK
talk to server… OK
version: 7.10.2</code></pre>



<p>Si ahora volvemos a acceder al dashboard, veremos como empiezan a aparecer los datos y los logs de los equipos.</p><p>The post <a href="https://www.dipler.org/2024/02/wazuh-no-muestra-informacion-de-los-equipos-de-repente/">Wazuh no muestra información de los equipos de repente</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.dipler.org/2024/02/wazuh-no-muestra-informacion-de-los-equipos-de-repente/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Cómo calcular diferencias de valor entre dos filas</title>
		<link>https://www.dipler.org/2021/09/como-calcular-diferencias-de-valor-entre-dos-filas/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=como-calcular-diferencias-de-valor-entre-dos-filas</link>
					<comments>https://www.dipler.org/2021/09/como-calcular-diferencias-de-valor-entre-dos-filas/#respond</comments>
		
		<dc:creator><![CDATA[Alejandro Escario]]></dc:creator>
		<pubDate>Wed, 01 Sep 2021 10:33:00 +0000</pubDate>
				<category><![CDATA[Bases de datos]]></category>
		<category><![CDATA[Postgres]]></category>
		<guid isPermaLink="false">https://www.dipler.org/?p=2288</guid>

					<description><![CDATA[<p>Pongamos que tenemos una aplicación como coingecko y estamos rastreando los exchanges para obtener un listado de los precios de cada símbolo. Para ello nos basamos en una tabla sencilla de Postgres (o incluso timescale). Obviamente nos hemos preocupado de optimizar en todo momento los particionamientos de las tablas, índices,<a class="moretag" href="https://www.dipler.org/2021/09/como-calcular-diferencias-de-valor-entre-dos-filas/"> Leer más</a></p>
<p>The post <a href="https://www.dipler.org/2021/09/como-calcular-diferencias-de-valor-entre-dos-filas/">Cómo calcular diferencias de valor entre dos filas</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Pongamos que tenemos una aplicación como <a href="https://www.coingecko.com/" title="https://www.coingecko.com/" target="_blank" rel="noreferrer noopener">coingecko</a> y estamos rastreando los exchanges para obtener un listado de los precios de cada símbolo. Para ello nos basamos en una tabla sencilla de <a href="https://www.dipler.org/tag/postgres/">Postgres</a> (o incluso <a href="https://www.timescale.com/" target="_blank" rel="noreferrer noopener">timescale</a>). <em>Obviamente nos hemos preocupado de optimizar en todo momento los particionamientos de las tablas, índices, etc.</em></p>



<p>De repente, en un proceso de auditoría o, simplemente al comparar los precios de dos exchanges para llevar a cabo un proceso de arbitraje, nos damos cuenta que, de algunos exanges, nos faltan datos. Es decir, no tenemos algunos precios y queremos poner solución a este problema.</p>



<p>La tabla en la que almacenamos los datos la hemos llamado ticks y tiene la siguiente estructura:</p>



<figure class="wp-block-image size-full"><a href="https://www.dipler.org/wp-content/uploads/2021/08/image.png"><img decoding="async" width="474" height="328" src="https://www.dipler.org/wp-content/uploads/2021/08/image.png" alt="" class="wp-image-2289" srcset="https://www.dipler.org/wp-content/uploads/2021/08/image.png 474w, https://www.dipler.org/wp-content/uploads/2021/08/image-300x208.png 300w" sizes="(max-width: 474px) 100vw, 474px" /></a></figure>



<p>Esta tabla almacena todas las <strong>velas</strong> o <strong>klines</strong> agrupadas por minuto. </p>



<p>Como nos hemos dado cuenta durante este proceso de auditoría de que nos faltan datos de algunos minutos, queremos hacer una <strong><em>select</em></strong> que itere en los más de <strong>2.000.000</strong> de registros y nos indique qué velas nos faltan para poder poner solución.</p>



<p>Mucha gente abordaría este problema mediante un bucle e iterando en el lenguaje de programación final o bien mediante un procedimiento almacenado. Sin embargo, existe una forma muy interesante de hacer esto con un único comando en PostgreSQL.</p>



<p>Supongamos que tenemos un subconjunto de datos como el siguiente:</p>



<figure class="wp-block-image"><img decoding="async" src="blob:https://www.dipler.org/4cc69b10-5419-45f8-b6ca-cf10c94ea8b6" alt=""/></figure>



<p>Pues bien, si queremos obtener la diferencia entre el valor de una fila y el valor de la anterior deberemos hacer uso de la función <strong>LAG()</strong>. Esta diferencia de valor entre filas es crucial para poder realizar la tarea que nos proponemos.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
LAG(expression &#x5B;,offset &#x5B;,default_value]]) 
OVER (
    &#x5B;PARTITION BY partition_expression, ... ]
    ORDER BY sort_expression &#x5B;ASC | DESC], ...
)
</pre></div>


<h3 class="wp-block-heading">Lag</h3>



<p>Esta función nos permitirá acceder a un dato de una fila distinta a la actual mediante los siguientes valores:</p>



<h4 class="wp-block-heading">a) Expresión</h4>



<p>Expresión que se evalúa en la fila que aparece en la fila indicada por el <em>offset</em>. Puede ser una <em>columna</em>, una <em>expresión</em> o una <em>subquery</em>.</p>



<h4 class="wp-block-heading">b) Offset</h4>



<p>Entero positivo que indica cuántas filas antes tiene que aplicar la expresión. El valor por defecto es <strong>1</strong>.</p>



<h4 class="wp-block-heading">c) Default_value</h4>



<p>Valor por defecto en caso de que el offset no se pueda aplicar. El valor por defecto es <em>NULL</em>.</p>



<h3 class="wp-block-heading">Over</h3>



<p>Indica las características del conjunto de datos sobre el que iterará.</p>



<h4 class="wp-block-heading">a) Partition by</h4>



<p>Permite dividir las filas en particiones sobre las que se aplicará la función <em>LAG()</em> se aplica. Por defecto se usará una única partición.</p>



<h4 class="wp-block-heading">b) Order by</h4>



<p>Permite especificar el orden de las filas sobre las que aplicaremos la función <em>LAG()</em>.</p>



<h2 class="wp-block-heading">Resolución del problema</h2>



<p>Sabiendo la estructura de la expresión, vamos a ir paso a paso:</p>



<p>Primero vamos a obtener todas las entradas para un símbolo en concreto:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
SELECT * 
FROM ticks 
WHERE symbol = &#039;ETHBTC&#039;;
</pre></div>


<figure class="wp-block-image size-full"><a href="https://www.dipler.org/wp-content/uploads/2021/08/image-9.png"><img decoding="async" width="1736" height="380" src="https://www.dipler.org/wp-content/uploads/2021/08/image-9.png" alt="" class="wp-image-2304" srcset="https://www.dipler.org/wp-content/uploads/2021/08/image-9.png 1736w, https://www.dipler.org/wp-content/uploads/2021/08/image-9-300x66.png 300w, https://www.dipler.org/wp-content/uploads/2021/08/image-9-768x168.png 768w, https://www.dipler.org/wp-content/uploads/2021/08/image-9-1024x224.png 1024w, https://www.dipler.org/wp-content/uploads/2021/08/image-9-1536x336.png 1536w" sizes="(max-width: 1736px) 100vw, 1736px" /></a></figure>



<p>Ahora queremos mostrar además de la fecha de cierre de la fila actual, la de la fila anterior:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
select close_time, lag(close_time) over (order by close_time), *
	from ticks 
	where symbol = &#039;ETHBTC&#039;
</pre></div>


<figure class="wp-block-image size-full"><a href="https://www.dipler.org/wp-content/uploads/2021/08/image-12.png"><img loading="lazy" decoding="async" width="2328" height="530" src="https://www.dipler.org/wp-content/uploads/2021/08/image-12.png" alt="" class="wp-image-2310"/></a></figure>



<p>Como se puede observar en esta imagen, en la primera fila, la columna lag tiene el valor <em>NULL</em> ya que no existe ninguna fila previa. Sin embargo, el valor de lag de la fila <strong>N </strong>tendrá el valor de la columna <em>close_time</em> de la fila <strong>N-1</strong>.</p>



<p>Ahora nos interesa , en lugar de obtener valores anteriores, vamos a a calcular el intervalo entre estas dos  filas.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
select close_time - lag(close_time) over (order by close_time) as &quot;interval&quot;, *
	from ticks 
	where symbol = &#039;ETHBTC&#039;
</pre></div>


<figure class="wp-block-image size-full"><a href="https://www.dipler.org/wp-content/uploads/2021/08/image-7.png"><img loading="lazy" decoding="async" width="1934" height="576" src="https://www.dipler.org/wp-content/uploads/2021/08/image-7.png" alt="" class="wp-image-2299"/></a></figure>



<p>Ahora queremos poder filtrar por el nuevo campo. Por desgracia no se puede filtrar por el campo <em>«interval»</em>. Por ello, deberemos hacer uso de una <strong>subselect</strong> para aplicar el filtro que deseemos u ordenar los datos finales en función de ese campo. En este caso, vamos a ver qué velas de <strong>1 minuto</strong> nos faltan buscando intervalos superiores a <em><strong>00:01:00</strong></em>.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
select * from (
select close_time - lag(close_time) over (order by close_time) as increase, close_time, lag(close_time) over (order by close_time), *
	from ticks 
	where symbol = &#039;ETHBTC&#039;
	) as tmp where increase &gt; &#039;00:01:00&#039;
</pre></div>


<p>Obteniendo el siguiente resultado:</p>



<figure class="wp-block-image size-full"><a href="https://www.dipler.org/wp-content/uploads/2021/08/image-5.png"><img loading="lazy" decoding="async" width="1948" height="658" src="https://www.dipler.org/wp-content/uploads/2021/08/image-5.png" alt="" class="wp-image-2295"/></a></figure>



<p>Ni que decir tiene, la función <strong>LAG</strong> no es gratuita en recursos y por ello hay que ejecutarla con cuidado y sólo cuando sea estrictamente necesario.</p><p>The post <a href="https://www.dipler.org/2021/09/como-calcular-diferencias-de-valor-entre-dos-filas/">Cómo calcular diferencias de valor entre dos filas</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.dipler.org/2021/09/como-calcular-diferencias-de-valor-entre-dos-filas/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Pipenv: gestión de dependencias en Python para dormir tranquilos</title>
		<link>https://www.dipler.org/2021/08/pipenv-gestion-de-dependencias-en-python-para-dormir-tranquilos/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=pipenv-gestion-de-dependencias-en-python-para-dormir-tranquilos</link>
					<comments>https://www.dipler.org/2021/08/pipenv-gestion-de-dependencias-en-python-para-dormir-tranquilos/#respond</comments>
		
		<dc:creator><![CDATA[Alejandro Escario]]></dc:creator>
		<pubDate>Thu, 26 Aug 2021 20:31:18 +0000</pubDate>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pipenv]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://www.dipler.org/?p=2268</guid>

					<description><![CDATA[<p>Uno de los puntos débiles de muchos lenguajes de programación es que no incluyen sistemas de gestión de dependencias y proyectos. Al menos no desde el momento de su creación o como herramienta oficial. Esto dificulta enormemente el desarrollo de proyectos grandes, y multi-módulo. Para solucionar esto, cada lenguaje cuenta<a class="moretag" href="https://www.dipler.org/2021/08/pipenv-gestion-de-dependencias-en-python-para-dormir-tranquilos/"> Leer más</a></p>
<p>The post <a href="https://www.dipler.org/2021/08/pipenv-gestion-de-dependencias-en-python-para-dormir-tranquilos/">Pipenv: gestión de dependencias en Python para dormir tranquilos</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Uno de los puntos débiles de muchos lenguajes de programación es que no incluyen sistemas de gestión de dependencias y proyectos. Al menos no desde el momento de su creación o como herramienta oficial. Esto dificulta enormemente el desarrollo de proyectos grandes, y multi-módulo. </p>



<p>Para solucionar esto, cada lenguaje cuenta con distintas soluciones oficiales y no oficiales que ayudan en esta gestión.</p>



<p>En el caso de <a href="https://www.dipler.org/tag/python/" target="_blank" rel="noreferrer noopener">Python</a> (igual que pasa en <a href="https://www.dipler.org/tag/php/" target="_blank" rel="noreferrer noopener">PHP</a> con composer y otros sistemas similares) tenemos la posibilidad de gestionar las dependencias de distintas maneras:</p>



<ul class="wp-block-list"><li>Dependencias instaladas de forma global.</li><li>Dependencias instaladas en un entorno virtual.</li></ul>



<p>En este artículo nos vamos a centrar en abordar el manejo de dependencias con la segunda opción. Ésta variante, a su vez puede llevarse a cabo de distintas formas.</p>



<p>La más directa consiste en trabajar directamente con <strong><em>pip</em></strong>, los ficheros de dependencias requeridas, etc. Sin embargo, un proceso que parece muy sencillo a simple vista, se puede acabar dificultando al trabajar con proyectos grandes o muy grandes o, incluso, multimódulo.</p>



<p>Para evitar que nos suceda esto, hay herramientas basadas en los mismos conceptos (e incluso las mismas herramientas) pero con un flujo de trabajo más controlado y bien definido. Permitiendo controlar mucho mejor las dependencias, aislando correctamente todas aquellas necesarias y excluyendo las innecesarias, etc.</p>



<p>En este artículo vamos a adentrarnos en el mundo de <a href="https://github.com/pypa/pipenv" target="_blank" rel="noreferrer noopener">Pipenv</a>. </p>



<figure class="wp-block-image size-large"><a href="https://www.dipler.org/wp-content/uploads/2021/08/pipenv.png"><img loading="lazy" decoding="async" width="869" height="1024" src="https://www.dipler.org/wp-content/uploads/2021/08/pipenv-869x1024.png" alt="" class="wp-image-2282" srcset="https://www.dipler.org/wp-content/uploads/2021/08/pipenv-869x1024.png 869w, https://www.dipler.org/wp-content/uploads/2021/08/pipenv-255x300.png 255w, https://www.dipler.org/wp-content/uploads/2021/08/pipenv-768x905.png 768w, https://www.dipler.org/wp-content/uploads/2021/08/pipenv.png 1072w" sizes="auto, (max-width: 869px) 100vw, 869px" /></a><figcaption>Logo de Pipenv</figcaption></figure>



<p><strong>Pipenv</strong> es una herramienta que tiene por objetivo facilitar el manejo de <strong>entornos virtuales</strong>, así como facilitar el proceso de <strong>gestión de dependencias y paquetes</strong>. Vamos a hacer un recorrido de la herramienta que nos permita descubrir parte del potencial de la herramienta.</p>



<h2 class="wp-block-heading">Instalación</h2>



<p>El presente artículo asume que estamos usando <strong>Python 3</strong>. Si no estamos seguros de la versión que tenemos instalada, podemos ejecutar el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
➜  python --version
Python 3.9.1
</pre></div>


<p>Teniendo en cuenta todo esto, vamos a ponernos manos a la obra y a instalar el paquete pipenv. Tenemos varias opciones:</p>



<h3 class="wp-block-heading">Mac OsX</h3>



<p>Podemos hacer uso de <strong><a href="https://brew.sh/index_es" target="_blank" rel="noreferrer noopener">hombrew</a></strong> para instalar fácilmente pipenv</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
➜  brew install pipenv
Updating Homebrew...
==&gt; Auto-updated Homebrew!
Updated 4 taps (microsoft/mssql-release, homebrew/core, homebrew/cask and homebrew/services).
==&gt; New Formulae
apt                                                   docuum                                                mailcatcher                                           pari-seadata-big
aws-vault                                             eigenpy                                               microsoft/mssql-release/msodbcsql17@17.8.1.1          procps
basis_universal                                       fanyi                                                 microsoft/mssql-release/mssql-tools@17.8.1.1          pyoxidizer
bubblewrap                                            firefoxpwa                                            newrelic-infra-agent                                  reproc
bupstash                                              fst                                                   notcurses                                             rsc_2fa
cargo-bloat                                           ghostunnel                                            onedrive                                              singularity
cargo-llvm-lines                                      h2c                                                   opensearch-dashboards                                 spot
cargo-outdated                                        i2c-tools                                             ots                                                   sql-lint
chrpath                                               influxdb-cli                                          pari-elldata                                          stylua
cilium-cli                                            joplin-cli                                            pari-galdata                                          wildmidi
cruft                                                 kn                                                    pari-galpol                                           xauth
datree                                                libaec                                                pari-seadata                                          xsel
==&gt; Updated Formulae
Updated 2099 formulae.
==&gt; Renamed Formulae
prestosql -&gt; trino
==&gt; Deleted Formulae
giter8                                                procyon-decompiler                                    terraform-provisioner-ansible                         tj
==&gt; New Casks
betterdiscord-installer    clock-signal               gosign                     leapp                      mimestream                 stork                      trezor-suite               wifi-explorer-pro
blackhole-64ch             duplicate-file-finder      infra                      maccleaner-pro             mweb-pro                   temurin                    vsd-viewer                 wing-personal
blockbench                 fluent-reader              jiohome                    memory-cleaner             open-video-downloader      touch-portal               vsdx-annotator             zebra2
clay                       foxglove-studio            kdocs                      midi-router-client         shottr                     transfer                   vym
==&gt; Updated Casks
Updated 890 casks.
==&gt; Deleted Casks
3cxphone                                   elpki                                      lightwright                                phonetrans                                 superbeam
agfeo-dashboard                            finisher-fluxx                             locklizard-safeguard-viewer                playnow                                    tbs-studio
anytrans                                   finisher-micro                             macclean                                   plecs-standalone                           thetube
anytrans-for-android                       finisher-neo                               macintosh-explorer                         pomolectron                                trufont
axe-electrum                               flow-e                                     modulair                                   privatus                                   uberconference
baiducloud                                 fluxcenter                                 mweb                                       pro-fit                                    unity-appletv-support-for-editor
boonzi                                     fm3-edit                                   noraswitch                                 qtum                                       unity-linux-il2cpp-support-for-editor
brooklite                                  imarisviewer                               obyte                                      qyooo                                      unity-macos-il2cpp-support-for-editor
colormunki-photo                           imobie-m1-app-checker                      open-ecard                                 rubitrack-pro                              utox
deadbeef                                   instant-articles-builder                   otter-browser                              s3stat-setup                               wanna
dnagedcom                                  instasizer                                 pastor                                     scrooo                                     wingpersonal
dragthing                                  jabt-flow                                  phonebrowse                                simplelink-msp432e4-sdk                    wolfram-player
dukto                                      jidusm                                     phoneclean                                 spectrum                                   youtube-dl-gui
eaccess                                    lektor                                     phonerescue                                stageplotpro                               zbuc-imgur

==&gt; Downloading https://ghcr.io/v2/homebrew/core/pipenv/manifests/2021.5.29
######################################################################## 100.0%
==&gt; Downloading https://ghcr.io/v2/homebrew/core/pipenv/blobs/sha256:3e01446c114bb70d72f7455b19417e9e3190a95dcd565dc4ce994988b1b49f54
==&gt; Downloading from https://pkg-containers.githubusercontent.com/ghcr1/blobs/sha256:3e01446c114bb70d72f7455b19417e9e3190a95dcd565dc4ce994988b1b49f54?se=2021-08-25T22%3A30%3A00Z&amp;sig=RwjOht74WcGb6QyObhAXlWI%2F31JHBb
######################################################################## 100.0%
==&gt; Pouring pipenv--2021.5.29.big_sur.bottle.tar.gz
==&gt; Caveats
zsh completions have been installed to:
  /usr/local/share/zsh/site-functions
==&gt; Summary
&amp;#x1f37a;  /usr/local/Cellar/pipenv/2021.5.29: 1,854 files, 28.2MB
==&gt; `brew cleanup` has not been run in 30 days, running now...
...
Pruned 2 symbolic links and 19 directories from /usr/local
</pre></div>


<h3 class="wp-block-heading">Otros</h3>



<p>Para dar soporte a cualquier plataforma, ya sea de las anteriormente mencionadas o cualquier otra, podemos hacer uso del paquete <strong>pip</strong> o <strong>pip3</strong>. Por ello, lo primero que tenemos que hacer es comprobar que tenemos instalado el gestor de paquetes pip en el equipo, para lo que ejecutaremos el comando pip o pip3:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
➜  pip3 --version
pip 20.2.3 from /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/pip (python 3.9)
</pre></div>


<p>Para posteriormente instalar el gestor de paquetes.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
➜  pip3 install pipenv
Collecting pipenv
  Using cached pipenv-2021.5.29-py2.py3-none-any.whl (3.9 MB)
Requirement already satisfied: virtualenv in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from pipenv) (20.7.2)
Requirement already satisfied: virtualenv-clone&gt;=0.2.5 in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from pipenv) (0.5.6)
Requirement already satisfied: setuptools&gt;=36.2.1 in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from pipenv) (49.2.1)
Requirement already satisfied: pip&gt;=18.0 in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from pipenv) (20.2.3)
Requirement already satisfied: certifi in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from pipenv) (2021.5.30)
Requirement already satisfied: distlib&lt;1,&gt;=0.3.1 in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from virtualenv-&gt;pipenv) (0.3.2)
Requirement already satisfied: filelock&lt;4,&gt;=3.0.0 in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from virtualenv-&gt;pipenv) (3.0.12)
Requirement already satisfied: six&lt;2,&gt;=1.9.0 in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from virtualenv-&gt;pipenv) (1.16.0)
Requirement already satisfied: backports.entry-points-selectable&gt;=1.0.4 in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from virtualenv-&gt;pipenv) (1.1.0)
Requirement already satisfied: platformdirs&lt;3,&gt;=2 in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from virtualenv-&gt;pipenv) (2.2.0)
Installing collected packages: pipenv
Successfully installed pipenv-2021.5.29
WARNING: You are using pip version 20.2.3; however, version 21.2.4 is available.
You should consider upgrading via the &#039;/Library/Frameworks/Python.framework/Versions/3.9/bin/python3.9 -m pip install --upgrade pip&#039; command.
</pre></div>


<p>Una vez instalado podremos comprobar la versión ejecutando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
➜   pipenv --version
pipenv, version 2021.5.29
</pre></div>


<h2 class="wp-block-heading">Conceptos básicos</h2>



<p>Como hemos dicho anteriormente <strong>Pipenv</strong> es un gestor de dependencias en entornos virtuales que facilita mucho el proceso de gestión del proyecto y, sobre todo, permite que un equipo trabaje con las mismas versiones de las dependencias y un ecosistema lo más parecido posible aunque se usen distintos equipos y configuraciones base. </p>



<p>Para ello, Pipenv se apoya en una serie de ficheros:</p>



<h3 class="wp-block-heading">Pipfile</h3>



<p>Este fichero contiene información básica del proyecto, así como las dependencias del mismo. Más adelante, veremos un ejemplo</p>



<h3 class="wp-block-heading">Pipfile.lock</h3>



<p>Fichero que complementa a Pipfile. Si bien este último permite identificar versiones genéricas de las librerías y otra información relevante, el fichero Pipfile.lock nos permite describir la configuración exacta del proyecto. Es decir, si en el primero decimos que queremos un paquete concreto en su versión 2, en el fichero Pipfile.lock queda definida la versión exacta de dicho paquete. Esto permite facilitar enormemente el flujo de trabajo de equipos de cualquier tamaño.</p>



<h2 class="wp-block-heading">Crear un proyecto con Pipenv</h2>



<p>Crear. unproyecto con Pipenv es muy sencillo. Para ello ejecutaremos el comando con el argumento &#8211;three para python 3 y &#8211;two para python 2</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
➜  pipenv --three
Creating a virtualenv for this project...
Pipfile: /Users/alejandro/workspace/python/Pipfile
Using /opt/local/bin/python3.9 (3.9.5) to create virtualenv...
⠇ Creating virtual environment...created virtual environment CPython3.9.5.final.0-64 in 471ms
  creator CPython3Posix(dest=/Users/alejandro/.local/share/virtualenvs/python-8t82TBKP, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/Users/alejandro/Library/Application Support/virtualenv)
    added seed packages: pip==21.2.3, setuptools==57.4.0, wheel==0.37.0
  activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator

&amp;#x2714; Successfully created virtual environment!
Virtualenv location: /Users/alejandro/.local/share/virtualenvs/python-8t82TBKP
Creating a Pipfile for this project...
</pre></div>


<p>Este comando ha creado el fichero Pipfile que hemos comentado anteriormente y que tendrá un contenido similar a:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&#x5B;&#x5B;source]]
url = &quot;https://pypi.org/simple&quot;
verify_ssl = true
name = &quot;pypi&quot;

&#x5B;packages]

&#x5B;dev-packages]

&#x5B;requires]
python_version = &quot;3.9&quot;
</pre></div>


<p>En este documento tenemos la definición del proyecto, los paquetes y paquetes de desarrollo necesarios para ejecutar nuestro proyecto y los elementos requeridos. De momento el fichero es muy simple. No obstante, poco a poco iremos viendo como crece y varía con los comandos que iremos ejecutando. </p>



<h2 class="wp-block-heading">Nuestro primer script</h2>



<p>Vamos a crear un script que obtenga el precio del bitcoin haciendo uso de la API pública de Coindesk: https://api.coindesk.com/v1/bpi/currentprice.json</p>



<p>Primero vamos a importar la librería necesaria para poder hacer peticiones HTTP:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
➜  pipenv install requests
Installing requests...
Adding requests to Pipfile&#039;s &#x5B;packages]...
&amp;#x2714; Installation Succeeded
Pipfile.lock not found, creating...
Locking &#x5B;dev-packages] dependencies...
Locking &#x5B;packages] dependencies...
Building requirements...
Resolving dependencies...
&amp;#x2714; Success!
Updated Pipfile.lock (fe5a22)!
Installing dependencies from Pipfile.lock (fe5a22)...
  &amp;#x1f40d;   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 0/0 — 00:00:00
To activate this project&#039;s virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
</pre></div>


<p>Perfecto, ya tenemos instalado el paquete requests. En este punto veremos que el fichero Pipfile tiene ahora el paquete que hemos indicado:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; highlight: [7]; title: ; notranslate">
&#x5B;&#x5B;source]]
url = &quot;https://pypi.org/simple&quot;
verify_ssl = true
name = &quot;pypi&quot;

&#x5B;packages]
requests = &quot;*&quot;

&#x5B;dev-packages]

&#x5B;requires]
python_version = &quot;3.9&quot;
</pre></div>


<p>Y que ha aparecido un fichero llamado Pipfile.lock que contiene el detalle de las dependencias y las versiones:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
{
    &quot;_meta&quot;: {
        &quot;hash&quot;: {
            &quot;sha256&quot;: &quot;b8c2e1580c53e383cfe4254c1f16560b855d984fde8b2beb3bf6ee8fc2fe5a22&quot;
        },
        &quot;pipfile-spec&quot;: 6,
        &quot;requires&quot;: {
            &quot;python_version&quot;: &quot;3.9&quot;
        },
        &quot;sources&quot;: &#x5B;
            {
                &quot;name&quot;: &quot;pypi&quot;,
                &quot;url&quot;: &quot;https://pypi.org/simple&quot;,
                &quot;verify_ssl&quot;: true
            }
        ]
    },
    &quot;default&quot;: {
        &quot;certifi&quot;: {
            &quot;hashes&quot;: &#x5B;
                &quot;sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee&quot;,
                &quot;sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8&quot;
            ],
            &quot;version&quot;: &quot;==2021.5.30&quot;
        },
        &quot;charset-normalizer&quot;: {
            &quot;hashes&quot;: &#x5B;
                &quot;sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b&quot;,
                &quot;sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3&quot;
            ],
            &quot;markers&quot;: &quot;python_version &gt;= &#039;3&#039;&quot;,
            &quot;version&quot;: &quot;==2.0.4&quot;
        },
        &quot;idna&quot;: {
            &quot;hashes&quot;: &#x5B;
                &quot;sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a&quot;,
                &quot;sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3&quot;
            ],
            &quot;markers&quot;: &quot;python_version &gt;= &#039;3&#039;&quot;,
            &quot;version&quot;: &quot;==3.2&quot;
        },
        &quot;requests&quot;: {
            &quot;hashes&quot;: &#x5B;
                &quot;sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24&quot;,
                &quot;sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7&quot;
            ],
            &quot;index&quot;: &quot;pypi&quot;,
            &quot;version&quot;: &quot;==2.26.0&quot;
        },
        &quot;urllib3&quot;: {
            &quot;hashes&quot;: &#x5B;
                &quot;sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4&quot;,
                &quot;sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f&quot;
            ],
            &quot;markers&quot;: &quot;python_version &gt;= &#039;2.7&#039; and python_version not in &#039;3.0, 3.1, 3.2, 3.3, 3.4&#039; and python_version &amp;lt; &#039;4&#039;&quot;,
            &quot;version&quot;: &quot;==1.26.6&quot;
        }
    },
    &quot;develop&quot;: {}
}
</pre></div>


<p>Como hemos comentado anteriormente, este fichero permitirá asegurarnos de que todos los miembros del equipo contamos con las mismas versiones de los paquetes.</p>



<p>Muy bien, ¿pero dónde está el entorno virtual con las dependencias instaladas? Es posible que hayas usado antes pip o los venv y te sorprenderá no ver la típica carpeta env o venv. Para ver su localización ejecutaremos el siguiente comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
➜  pipenv --venv
/Users/alejandro/.local/share/virtualenvs/python-8t82TBKP
</pre></div>


<p>Esto es así porque no tenemos habilitada la opción de generar la carpeta venv en el proyecto, sino que la crea fuera.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
➜  export PIPENV_VENV_IN_PROJECT=&quot;enabled&quot;
</pre></div>


<p>Ambas opciones son válidas. Si una vez habilitada esta variable de entorno volvemos a ejecutar el comando de vgeneración del proyecto, veremos qyue tenemos una carpeta llamada .venv.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
➜  pipenv --three
Creating a virtualenv for this project...
Pipfile: /Users/alejandro/workspace/python/Pipfile
Using /opt/local/bin/python3.9 (3.9.5) to create virtualenv...
⠹ Creating virtual environment...created virtual environment CPython3.9.5.final.0-64 in 730ms
  creator CPython3Posix(dest=/Users/alejandro/workspace/python/.venv, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/Users/alejandro/Library/Application Support/virtualenv)
    added seed packages: pip==21.2.3, setuptools==57.4.0, wheel==0.37.0
  activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator

&amp;#x2714; Successfully created virtual environment!
Virtualenv location: /Users/alejandro/workspace/python/.venv
➜  ls -la
total 16
drwxr-xr-x     5 alejandro  staff    160 26 ago 01:05 .
drwx------@ 1344 alejandro  staff  43008 25 ago 23:56 ..
drwxr-xr-x     7 alejandro  staff    224 26 ago 01:05 .venv
-rw-r--r--     1 alejandro  staff    153 26 ago 00:51 Pipfile
-rw-r--r--     1 alejandro  staff   2147 26 ago 00:52 Pipfile.lock
</pre></div>


<p>Activar el entorno virutal es tan sencillo como ejecutar el comando:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
➜  pipenv shell
Launching subshell in virtual environment...
 . /Users/alejandro/.local/share/virtualenvs/crawler-JJA5iozN/bin/activate
➜  . /Users/alejandro/.local/share/virtualenvs/crawler-JJA5iozN/bin/activate
(python) ➜  
</pre></div>


<p>El hecho de que aparezca un nombre enter paréntesis antes del prompt quiere decir que estamos dentro del entorno virtual.</p>



<p>Si queremos crear el entorno virtual a partir de un proyecto descargado de un repositorio, bastaría con ejecutar el comando:</p>



<p>pip install</p>



<h2 class="wp-block-heading">El primer programa</h2>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: python; title: ; notranslate">
import requests

response = requests.get(&#039;https://api.coindesk.com/v1/bpi/currentprice.json&#039;)
json = response.json()

print(f&quot;{json&#x5B;&#039;bpi&#039;]&#x5B;&#039;USD&#039;]&#x5B;&#039;rate&#039;]} @ {json&#x5B;&#039;time&#039;]&#x5B;&#039;updated&#039;]}&quot;)
</pre></div>


<p>Y si ahora lo ejecutamos obtendremos la siguiente salida:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
(python) ➜ python test.py
49,033.6041 @ Aug 25, 2021 23:19:00 UTC
</pre></div>


<p>Con este pequeño ejemplo hemos hecho un recorrido completo en el que se expone el manejo. deproyectos y dependencias con Pipenv. No obstante, es una herramienta con muchas más posibilidades de las que hemos podido ver en el artículo. </p>



<p>Os dejo un link a una página en la que podéis ver más información: <a href="https://pipenv-es.readthedocs.io/es/latest/">Pipenv: Flujo de trabajo en Python para humanos. — documentación de pipenv &#8211; 2018.05.18 (pipenv-es.readthedocs.io)</a>.</p>



<p>Otra opción es ejecutar el comando pipenv &#8211;man. Este comando mostrará en consola la documentación completa del comando con detalles de su uso y sus opciones.</p><p>The post <a href="https://www.dipler.org/2021/08/pipenv-gestion-de-dependencias-en-python-para-dormir-tranquilos/">Pipenv: gestión de dependencias en Python para dormir tranquilos</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.dipler.org/2021/08/pipenv-gestion-de-dependencias-en-python-para-dormir-tranquilos/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>¡Deja de usar i++ en tus bucles de PHP!</title>
		<link>https://www.dipler.org/2021/07/deja-de-usar-i-en-tus-bucles-de-php/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=deja-de-usar-i-en-tus-bucles-de-php</link>
					<comments>https://www.dipler.org/2021/07/deja-de-usar-i-en-tus-bucles-de-php/#respond</comments>
		
		<dc:creator><![CDATA[Alejandro Escario]]></dc:creator>
		<pubDate>Fri, 23 Jul 2021 21:11:07 +0000</pubDate>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Optimización]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://www.dipler.org/?p=2230</guid>

					<description><![CDATA[<p>En PHP es muy común el uso de los bucles for y foreach (casi más que los while y do-while) para realizar tareas sobre elementos iterables. El bucle foreach recorre los distintos elementos sin necesidad de contadores externos; sin embargo, los bucles for, while y do-while necesitan condiciones de salida<a class="moretag" href="https://www.dipler.org/2021/07/deja-de-usar-i-en-tus-bucles-de-php/"> Leer más</a></p>
<p>The post <a href="https://www.dipler.org/2021/07/deja-de-usar-i-en-tus-bucles-de-php/">¡Deja de usar i++ en tus bucles de PHP!</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>En PHP es muy común el uso de los bucles <strong>for</strong> y <strong>foreach</strong> (casi más que los <strong>while</strong> y <strong>do-while</strong>) para realizar tareas sobre elementos <em>iterables</em>. El bucle <strong>foreach</strong> recorre los distintos elementos sin necesidad de contadores externos; sin embargo, los bucles <strong>for</strong>, <strong>while</strong> y <strong>do-while</strong> necesitan condiciones de salida y, a menudo, contadores.</p>



<p>Sustituir $i++ por ++$i es uno de los más de <a href="https://www.dipler.org/2009/10/20-consejos-para-optimizar-tus-codigos-php/" target="_blank" rel="noreferrer noopener">20 consejos de optimización de códigos PHP</a> que describimos en 2009. Si bien desde ese año, muchos lenguajes han hecho mejoras al respecto, como Java, PHP no ha tenido la misma suerte.</p>



<p>Con la actualización a <strong><a href="https://php.net" title="https://php.net" target="_blank" rel="noreferrer noopener">PHP</a> 7</strong> se ha optimizado la velocidad de ejecución de los scripts gracias a un motor de ejecución renovado. No obstante, sigue siendo un código interpretado. </p>



<p>Los lenguajes <em>compilados</em> o <em>transpilados</em>, como <strong>Java</strong>, <strong>C</strong> o <strong>Rust</strong> permiten realizar optimizaciones automáticas durante el proceso de conversión a <em>código máquina</em> o <em>bytecode</em>. Sin embargo, en lenguajes de scripting, como PHP, esto no es así. Estos lenguajes no realizan varias pasadas de forma previa a la ejecución que permitan buscar patrones de optimización automática. Al menos no sin afectar gravemente al  rendimiento. </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Vale, es cierto, existen sistemas que permiten cachea el código, almacenarlo en memoria, etc. Con la finalidad de acelerar significativamente el tiempo de ejecución.</p><p></p></blockquote>



<h2 class="wp-block-heading">Teoría</h2>



<p>Con la finalidad de entender los resultados, antes vamos a analizar detenidamente lo que sucede con cada una de las posibilidades básicas que tenemos para incrementar en 1 un valor.</p>



<p>Para hacer este análisis vamos a hacer uso de la herramienta <strong><a href="https://php.watch/articles/php-dump-opcodes" target="_blank" rel="noreferrer noopener" title="https://php.watch/articles/php-dump-opcodes">phpdbg</a></strong> con el código</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
~$ phpdbg -p &lt;archivo&gt;
</pre></div>


<p>Phpdbg con el parámetro -p nos permite listar los opcodes de un script.</p>



<h3 class="wp-block-heading">Post-incremento [$i++]</h3>



<p>Para el código</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php
$i = 0;
$i++;
</pre></div>


<p>Si analizamos el opcode generado</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; highlight: [6,7,8]; title: ; notranslate">
~$ phpdbg -p 001_additions_i++.php
function name: (null)
L1-3 {main}() ./20210718 PHP optimization/001_additions_i++.php - 0x10967e7e0 + 6 ops
 L2    #0     EXT_STMT                                                                              
 L2    #1     ASSIGN                  $i                   0                                        
 L3    #2     EXT_STMT                                                                              
 L3    #3     POST_INC                $i                                        ~1                  
 L3    #4     FREE                    ~1                                                            
 L3    #5     RETURN&lt;-1&gt;              1               
&#x5B;Script ended normally]                                                            
</pre></div>


<p>Vemos como las líneas marcadas (#2-#4) son las que se corresponden con $i++: </p>



<ol class="wp-block-list"><li><strong>EX_STMT</strong>: la podemos obviar porque es la que ejecuta el statement.</li><li><strong>POST_INC</strong>: realiza un post_incremento. Este incremento debe almacenar el resultado para luego devolverlo.</li><li><strong>FREE</strong>: libera el valor una vez devuelto.</li></ol>



<p>En este caso, el valor de <strong>$i++</strong> devolvería, según la iteración:</p>



<ul class="wp-block-list"><li>Iteración 0 => 0</li><li>Iteración 1 => 1</li><li>Iteración 2 => 2</li><li>&#8230;</li><li>Iteración n => n</li></ul>



<h3 class="wp-block-heading">Pre-incremento [++$i]</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php
$i = 0;
++$i;
</pre></div>


<p>De forma análoga al caso anterior, se incrementa el valor de la variable en 1, sin embargo, en este caso se realizan menos operaciones a bajo nivel, realizando el incremento antes de obtener el valor.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; highlight: [6,7]; title: ; notranslate">
~$ phpdbg -p 001_additions_++i.php
function name: (null)
L1-3 {main}() ./20210718 PHP optimization/001_additions_i++.php - 0x10a08c000 + 5 ops
 L2    #0     EXT_STMT                                                                              
 L2    #1     ASSIGN                  $i                   0                                        
 L3    #2     EXT_STMT                                                                              
 L3    #3     PRE_INC                 $i                                                            
 L3    #4     RETURN&lt;-1&gt;              1                                                             
&#x5B;Script ended normally]
</pre></div>


<ol class="wp-block-list"><li><strong>EX_STMT</strong>: la podemos obviar porque es la que ejecuta el statement.</li><li><strong>PRE_INC</strong>: realiza un pre_incremento. En este caso al no tener que almacenar el valor intermedio para devolverlo, no hay que liberarlo a posteriori.</li></ol>



<p>De este modo, el código, para cada iteración, la instrucción <strong>++$i</strong> devolverá:</p>



<ul class="wp-block-list"><li>Iteración 0 => 1</li><li>Iteración 1 => 2</li><li>Iteración 2 => 3</li><li>&#8230;</li><li>Iteración n => n+1</li></ul>



<p>Es decir, se ahorran opcodes a bajo nivel con respecto al <strong>$i++</strong>, es decir, teóricamente debería de ser más rápido.</p>



<h3 class="wp-block-heading">Suma [$i = $i + 1]</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php
$i = 0;
$i = $i + 1;
</pre></div>

<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; highlight: [6,7,8]; title: ; notranslate">
~$ phpdbg -p 001_additions_i=i+1.php 
function name: (null)
L1-3 {main}() ./20210718 PHP optimization/001_additions_i=i+1.php - 0x10528b100 + 6 ops
 L2    #0     EXT_STMT                                                                              
 L2    #1     ASSIGN                  $i                   0                                        
 L3    #2     EXT_STMT                                                                              
 L3    #3     ADD                     $i                   1                    ~1                  
 L3    #4     ASSIGN                  $i                   ~1                                       
 L3    #5     RETURN&lt;-1&gt;              1                                                             
&#x5B;Script ended normally]
</pre></div>


<p>Este bucle, el incremento realiza una suma de un entero, es decir, no es exactamente un incremento aunque el resultado sea el mismo. Pero obtiene un valor, suma un valor constante y, finalmente almacena el valor. En opcodes:</p>



<ol class="wp-block-list"><li><strong>EX_STMT:</strong> la podemos obviar porque es la que ejecuta el statement.</li><li><strong>ADD:</strong> ejecuta la adición de los dos valores</li><li><strong>ASSIGN:</strong> asigna el valor a $i</li></ol>



<h3 class="wp-block-heading">Suma acortada [$i += 1]</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php
$i = 0;
$i += 1;
</pre></div>

<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; highlight: [6,7]; title: ; notranslate">
~$ phpdbg -p 001_additions_i+=1.php 
function name: (null)
L1-3 {main}() ./20210718 PHP optimization/001_additions_i+=1.php - 0x11227e7e0 + 5 ops
 L2    #0     EXT_STMT                                                                              
 L2    #1     ASSIGN                  $i                   0                                        
 L3    #2     EXT_STMT                                                                              
 L3    #3     ASSIGN_ADD              $i                   1                                        
 L3    #4     RETURN&lt;-1&gt;              1                                                             
&#x5B;Script ended normally]
</pre></div>


<p>De forma similar al caso anterior se realiza una suma pero sin devolver el valor <strong>$i</strong> inicialmente (realiza una operación menos, reduciendo en varios opcodes cada iteración), por lo que debería de ser algo más rápido que la suma tradicional y que el post-incremento. </p>



<p>Vamos a analizarlo:</p>



<ol class="wp-block-list"><li><strong>EX_STMT:</strong> la podemos obviar porque es la que ejecuta el statement.</li><li><strong>ASSIGN_ADD:</strong> ejecuta la adición de los dos valores y la asigna en el mismo opcode.</li></ol>



<h2 class="wp-block-heading">Resultados teóricos</h2>



<p>Según los opcodes analizados anteriormente, podríamos intentar definir las formas más y menos costosas de realizar estas operaciones. En este caso, según los opcode, claramente el ++$i sería la opción más rápida, mientras que $i = $i + 1 sería la más lenta. </p>



<p>Entre $i++ y $i+=1, podríamos decantarnos por que, a pesar de que añadir es más costoso que incrementar, nos ahorramos la tarea de liberar. Por ello el orden teórico según los opcode sería:</p>



<ul class="wp-block-list"><li>++$i: 2op code</li><li>$i+=1: 2 opcode</li><li>$i++: 3 opcode</li><li>$i=$i+1: 3 opcode</li></ul>



<h2 class="wp-block-heading">Código para el análisis</h2>



<p>Para ilustrar y analizar el caso del pre-incremento, post-incremento y dos tipos de operación suma, vamos a hacer un pequeño test que evalúe el rendimiento en PHP.</p>



<p>El script que vamos a utilizar para realizar las pruebas de rendimiento es el siguiente:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php
define(&#039;ITERATIONS&#039;, 1000000000);
define(&#039;TIMES&#039;, 100);
$result_array = &#x5B;
    &#039;$i++&#039; =&gt; array(),
    &#039;++$i&#039; =&gt; array(),
    &#039;$i+=1&#039; =&gt; array(),
    &#039;$i=$i+1&#039; =&gt; array(),
];

for ($j = 0; $j &lt; TIMES; $j++) {
    /**
     * i++ enlapsed time
     */
    $start = microtime(true);
    for ($i = 0; $i &lt; ITERATIONS; $i++);
    $time_elapsed_secs = microtime(true) - $start;
    echo &#039;$i++ (&#039;, ITERATIONS,&#039; times) took &#039;, $time_elapsed_secs, &quot;s\n&quot;;
    $result_array&#x5B;&#039;$i++&#039;]&#x5B;] = $time_elapsed_secs;


    /**
     * ++i enlapsed time
     */
    $start = microtime(true);
    for ($i = 0; $i &lt; ITERATIONS; ++$i);
    $time_elapsed_secs = microtime(true) - $start;
    echo &#039;++$i (&#039;, ITERATIONS,&#039; times) took &#039;, $time_elapsed_secs, &quot;s\n&quot;;
    $result_array&#x5B;&#039;++$i&#039;]&#x5B;] = $time_elapsed_secs;


    /**
     * $i+=1 enlapsed time
     */
    $start = microtime(true);
    for ($i = 0; $i &lt; ITERATIONS; $i+=1);
    $time_elapsed_secs = microtime(true) - $start;
    echo &#039;$i += 1 (&#039;, ITERATIONS,&#039; times) took &#039;, $time_elapsed_secs, &quot;s\n&quot;;
    $result_array&#x5B;&#039;$i+=1&#039;]&#x5B;] = $time_elapsed_secs;

    /**
     * $i= $i+1 enlapsed time
     */
    $start = microtime(true);
    for ($i = 0; $i &lt; ITERATIONS; $i=$i + 1);
    $time_elapsed_secs = microtime(true) - $start;
    echo &#039;$i = $i + 1 (&#039;, ITERATIONS,&#039; times) took &#039;, $time_elapsed_secs, &quot;s\n&quot;;
    $result_array&#x5B;&#039;$i=$i+1&#039;]&#x5B;] = $time_elapsed_secs;
}

$fp = fopen(&#039;001_additions.csv&#039;, &#039;w&#039;);

foreach ($result_array as $key =&gt; $row) {
    array_unshift($row, $key);
    fputcsv($fp, $row);
}

fclose($fp);
</pre></div>


<p>El código, si se analiza en detalle, veremos cómo ejecuta <em>100</em> veces cada una de las cuatro pruebas. En cada prueba ejecutará <em>1.000.000.000</em> (mil millones de veces) la operación suma (además de comparaciones y moverá el puntero de ejecución). Además, para cada una de las <em>100</em> iteraciones, ejecutaremos cuatro tipos de incremento distintas. El resultado de cada prueba se almacenará en una variable que se utilizará para generar finalmente un CSV que podremos analizar.</p>



<h2 class="wp-block-heading">Resultados</h2>



<p>La ejecución de una única iteración nos muestra los siguientes resultados:</p>



<p><strong>$i++</strong> (1000000000 times) took <strong>13.006237030029s</strong><br><strong>++$i</strong> (1000000000 times) took <strong>9.5504179000854s</strong><br><strong>$i += 1</strong> (1000000000 times) took <strong>11.834012031555s</strong><br><strong>$i = $i + 1</strong> (1000000000 times) took <strong>14.221917152405s</strong></p>



<p>Estos resultados podrían verse afectados por las tareas que se están realizando en paralelo en el equipo, por lo que, para mejorar el análisis, se ejecutan 100 veces cada una de los bucles de forma intercalada, permitiendo reducir la variabilidad en los tiempos asociada a la carga del equipo en otras tareas.</p>



<p>La ejecución se realiza en un <strong><a href="https://amzn.to/2TwXvv1" title="https://amzn.to/2TwXvv1">Macbook Pro de 15&#8243;</a></strong> con <strong>16GB</strong> de RAM y PHP <strong>7.3</strong>.</p>



<p>Tras ejecutar 100 veces el test completo obtenemos los siguientes resultados:</p>



<figure class="wp-block-image size-large"><a href="https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-23-a-las-16.48.28.png"><img loading="lazy" decoding="async" width="1024" height="641" src="https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-23-a-las-16.48.28-1024x641.png" alt="" class="wp-image-2231" srcset="https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-23-a-las-16.48.28-1024x641.png 1024w, https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-23-a-las-16.48.28-300x188.png 300w, https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-23-a-las-16.48.28-768x481.png 768w, https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-23-a-las-16.48.28-1536x962.png 1536w, https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-23-a-las-16.48.28.png 2012w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>


<a  data-e-Disable-Page-Transition="true" class="download-link" title="Versión 1.0" href="https://www.dipler.org/download/2249/?tmstv=1775265104" rel="nofollow" id="download-link-2249" data-redirect="false" >
	CSV php increment times	(513 descargas	)
</a>




<p>A menor valor, menor tiempo de ejecución y por lo tanto es una aproximación de ejecución más rápida.</p>



<p>Como puede observarse, los datos ejecutados 100 veces son consistentes con los de la primera ejecución que hemos mostrado más arriba y, si somos algo curiosos, podemos observar cómo ha ido variando la carga del equipo durante las horas que duró la prueba.</p>



<p>Además de ver una clara diferencia que es consistente, podemos ver como hay unas variaciones de hasta el 50% en el tiempo de ejecución haciendo uso de las diferentes sintaxis, siendo el pre-incremento la opción claramente ganadora y el incremento en formato suma tradicional el más costoso.</p>



<h2 class="wp-block-heading">Conclusiones</h2>



<p>Cada forma de incrementar un valor tiene sus ventajas e inconvenientes como hemos visto en este artículo porque cubren necesidades diferentes. No obstante, para bucles for hay un claro ganador: el pre-incremento <strong>++$i</strong>.</p>



<p>En la inmensa mayoría de los casos, no notaremos mejoras de rendimiento significativas. Esto es así porque normalmente la carga de la ejecución de un bucle viene dada por el contenido del mismo. Es decir, el número de instrucciones a bajo nivel ejecutadas en el cuerpo del bucle suele ser muy superior al del cálculo del propio bucle.</p>



<p>En cualquier caso, esta optimización debería preocuparnos únicamente en el caso de ejecutar grandes tareas por lotes o contar con una gran cantidad de visitas en paralelo.</p>



<p>No obstante, y aunque sobre el código final a ejecutar pueda no tener un gran impacto de tiempo, todo suma; sobre todo si es cambiar una costumbre y poner el símbolo de suma antes de la variable en lugar de después.</p><p>The post <a href="https://www.dipler.org/2021/07/deja-de-usar-i-en-tus-bucles-de-php/">¡Deja de usar i++ en tus bucles de PHP!</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.dipler.org/2021/07/deja-de-usar-i-en-tus-bucles-de-php/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Instalando y utilizando Debugbar en Lumen</title>
		<link>https://www.dipler.org/2021/07/instalando-y-utilizando-debugbar-en-lumen/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=instalando-y-utilizando-debugbar-en-lumen</link>
					<comments>https://www.dipler.org/2021/07/instalando-y-utilizando-debugbar-en-lumen/#respond</comments>
		
		<dc:creator><![CDATA[Alejandro Escario]]></dc:creator>
		<pubDate>Wed, 14 Jul 2021 09:32:00 +0000</pubDate>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Lumen]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://www.dipler.org/?p=2188</guid>

					<description><![CDATA[<p>Existen multitud de proyectos para ayudar en las tareas de debug y mantenimiento de proyectos basados en Laravel. Sin embargo, el número de proyectos dedicados a esta tarea disminuye drásticamente cuando queremos desarrollar un proyecto en Lumen. Lumen tiene una gran cantidad de ventajas con respecto a su hermano mayor<a class="moretag" href="https://www.dipler.org/2021/07/instalando-y-utilizando-debugbar-en-lumen/"> Leer más</a></p>
<p>The post <a href="https://www.dipler.org/2021/07/instalando-y-utilizando-debugbar-en-lumen/">Instalando y utilizando Debugbar en Lumen</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Existen multitud de proyectos para ayudar en las tareas de debug y mantenimiento de proyectos basados en Laravel. Sin embargo, el número de proyectos dedicados a esta tarea disminuye drásticamente cuando queremos desarrollar un proyecto en Lumen.</p>



<p>Lumen tiene una gran cantidad de ventajas con respecto a su hermano mayor si vamos a definir una API. Pero entre las desventajas que tiene es que no siempre se encuentra tanta documentación ni librerías adaptadas.</p>



<p>En este artículo vamos a describir paso a paso cómo crear un proyecto basado en Lumen 8, instalar el plugin de <a href="https://github.com/barryvdh/laravel-debugbar" target="_blank" rel="noreferrer noopener">debugbar</a> y configurarlo sin romper la API.</p>



<p><strong>Creación del proyecto</strong></p>



<p>El primer paso es crear el proyecto Lumen. Si ya tienes un proyecto sobre el que desees usar el paquete, puedes pasar al siguiente punto.</p>


<div class="wp-block-syntaxhighlighter-code max-height-300"><pre class="brush: bash; highlight: [1]; title: ; notranslate">
~$ composer create-project --prefer-dist laravel/lumen debugbar_lumen                                                  
Creating a &quot;laravel/lumen&quot; project at &quot;./debugbar_lumen&quot;
Installing laravel/lumen (v8.1.1)
  - Installing laravel/lumen (v8.1.1): Extracting archive
Created project in ./20210712 Debugbar laravel/debugbar_lumen
&gt; @php -r &quot;file_exists(&#039;.env&#039;) || copy(&#039;.env.example&#039;, &#039;.env&#039;);&quot;
Loading composer repositories with package information
Updating dependencies
Lock file operations: 106 installs, 0 updates, 0 removals
  - Locking brick/math (0.9.2)
  - Locking doctrine/inflector (2.0.3)
  - Locking doctrine/instantiator (1.4.0)
  - Locking doctrine/lexer (1.2.1)
  - Locking dragonmantank/cron-expression (v3.1.0)
  - Locking egulias/email-validator (2.1.25)
  - Locking fakerphp/faker (v1.15.0)
  - Locking graham-campbell/result-type (v1.0.1)
  - Locking hamcrest/hamcrest-php (v2.0.1)
  - Locking illuminate/auth (v8.49.2)
  - Locking illuminate/broadcasting (v8.49.2)
  - Locking illuminate/bus (v8.49.2)
  - Locking illuminate/cache (v8.49.2)
  - Locking illuminate/collections (v8.49.2)
  - Locking illuminate/config (v8.49.2)
  - Locking illuminate/console (v8.49.2)
  - Locking illuminate/container (v8.49.2)
  - Locking illuminate/contracts (v8.49.2)
  - Locking illuminate/database (v8.49.2)
  - Locking illuminate/encryption (v8.49.2)
  - Locking illuminate/events (v8.49.2)
  - Locking illuminate/filesystem (v8.49.2)
  - Locking illuminate/hashing (v8.49.2)
  - Locking illuminate/http (v8.49.2)
  - Locking illuminate/log (v8.49.2)
  - Locking illuminate/macroable (v8.49.2)
  - Locking illuminate/pagination (v8.49.2)
  - Locking illuminate/pipeline (v8.49.2)
  - Locking illuminate/queue (v8.49.2)
  - Locking illuminate/session (v8.49.2)
  - Locking illuminate/support (v8.49.2)
  - Locking illuminate/testing (v8.49.2)
  - Locking illuminate/translation (v8.49.2)
  - Locking illuminate/validation (v8.49.2)
  - Locking illuminate/view (v8.49.2)
  - Locking laravel/lumen-framework (v8.2.4)
  - Locking mockery/mockery (1.4.3)
  - Locking monolog/monolog (2.3.0)
  - Locking myclabs/deep-copy (1.10.2)
  - Locking nesbot/carbon (2.50.0)
  - Locking nikic/fast-route (v1.3.0)
  - Locking nikic/php-parser (v4.11.0)
  - Locking opis/closure (3.6.2)
  - Locking phar-io/manifest (2.0.1)
  - Locking phar-io/version (3.1.0)
  - Locking phpdocumentor/reflection-common (2.2.0)
  - Locking phpdocumentor/reflection-docblock (5.2.2)
  - Locking phpdocumentor/type-resolver (1.4.0)
  - Locking phpoption/phpoption (1.7.5)
  - Locking phpspec/prophecy (1.13.0)
  - Locking phpunit/php-code-coverage (9.2.6)
  - Locking phpunit/php-file-iterator (3.0.5)
  - Locking phpunit/php-invoker (3.1.1)
  - Locking phpunit/php-text-template (2.0.4)
  - Locking phpunit/php-timer (5.0.3)
  - Locking phpunit/phpunit (9.5.6)
  - Locking psr/container (1.1.1)
  - Locking psr/event-dispatcher (1.0.0)
  - Locking psr/log (1.1.4)
  - Locking psr/simple-cache (1.0.1)
  - Locking ramsey/collection (1.1.3)
  - Locking ramsey/uuid (4.1.1)
  - Locking sebastian/cli-parser (1.0.1)
  - Locking sebastian/code-unit (1.0.8)
  - Locking sebastian/code-unit-reverse-lookup (2.0.3)
  - Locking sebastian/comparator (4.0.6)
  - Locking sebastian/complexity (2.0.2)
  - Locking sebastian/diff (4.0.4)
  - Locking sebastian/environment (5.1.3)
  - Locking sebastian/exporter (4.0.3)
  - Locking sebastian/global-state (5.0.3)
  - Locking sebastian/lines-of-code (1.0.3)
  - Locking sebastian/object-enumerator (4.0.4)
  - Locking sebastian/object-reflector (2.0.4)
  - Locking sebastian/recursion-context (4.0.4)
  - Locking sebastian/resource-operations (3.0.3)
  - Locking sebastian/type (2.3.4)
  - Locking sebastian/version (3.0.2)
  - Locking symfony/console (v5.3.2)
  - Locking symfony/deprecation-contracts (v2.4.0)
  - Locking symfony/error-handler (v5.3.3)
  - Locking symfony/event-dispatcher (v5.3.0)
  - Locking symfony/event-dispatcher-contracts (v2.4.0)
  - Locking symfony/finder (v5.3.0)
  - Locking symfony/http-client-contracts (v2.4.0)
  - Locking symfony/http-foundation (v5.3.3)
  - Locking symfony/http-kernel (v5.3.3)
  - Locking symfony/mime (v5.3.2)
  - Locking symfony/polyfill-ctype (v1.23.0)
  - Locking symfony/polyfill-intl-grapheme (v1.23.0)
  - Locking symfony/polyfill-intl-idn (v1.23.0)
  - Locking symfony/polyfill-intl-normalizer (v1.23.0)
  - Locking symfony/polyfill-mbstring (v1.23.0)
  - Locking symfony/polyfill-php72 (v1.23.0)
  - Locking symfony/polyfill-php73 (v1.23.0)
  - Locking symfony/polyfill-php80 (v1.23.0)
  - Locking symfony/process (v5.3.2)
  - Locking symfony/service-contracts (v2.4.0)
  - Locking symfony/string (v5.3.3)
  - Locking symfony/translation (v5.3.3)
  - Locking symfony/translation-contracts (v2.4.0)
  - Locking symfony/var-dumper (v5.3.3)
  - Locking theseer/tokenizer (1.2.0)
  - Locking vlucas/phpdotenv (v5.3.0)
  - Locking voku/portable-ascii (1.5.6)
  - Locking webmozart/assert (1.10.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 106 installs, 0 updates, 0 removals
  - Installing doctrine/inflector (2.0.3): Extracting archive
  - Installing symfony/polyfill-php72 (v1.23.0): Extracting archive
  - Installing symfony/polyfill-intl-normalizer (v1.23.0): Extracting archive
  - Installing symfony/polyfill-intl-idn (v1.23.0): Extracting archive
  - Installing doctrine/lexer (1.2.1): Extracting archive
  - Installing egulias/email-validator (2.1.25): Extracting archive
  - Installing symfony/deprecation-contracts (v2.4.0): Extracting archive
  - Installing psr/container (1.1.1): Extracting archive
  - Installing fakerphp/faker (v1.15.0): Extracting archive
  - Installing symfony/polyfill-php80 (v1.23.0): Extracting archive
  - Installing symfony/polyfill-mbstring (v1.23.0): Extracting archive
  - Installing symfony/http-foundation (v5.3.3): Extracting archive
  - Installing symfony/finder (v5.3.0): Extracting archive
  - Installing voku/portable-ascii (1.5.6): Extracting archive
  - Installing symfony/translation-contracts (v2.4.0): Extracting archive
  - Installing symfony/translation (v5.3.3): Extracting archive
  - Installing nesbot/carbon (2.50.0): Extracting archive
  - Installing illuminate/macroable (v8.49.2): Extracting archive
  - Installing psr/simple-cache (1.0.1): Extracting archive
  - Installing illuminate/contracts (v8.49.2): Extracting archive
  - Installing illuminate/collections (v8.49.2): Extracting archive
  - Installing illuminate/support (v8.49.2): Extracting archive
  - Installing illuminate/filesystem (v8.49.2): Extracting archive
  - Installing illuminate/session (v8.49.2): Extracting archive
  - Installing symfony/polyfill-ctype (v1.23.0): Extracting archive
  - Installing phpoption/phpoption (1.7.5): Extracting archive
  - Installing graham-campbell/result-type (v1.0.1): Extracting archive
  - Installing vlucas/phpdotenv (v5.3.0): Extracting archive
  - Installing symfony/var-dumper (v5.3.3): Extracting archive
  - Installing symfony/mime (v5.3.2): Extracting archive
  - Installing symfony/polyfill-php73 (v1.23.0): Extracting archive
  - Installing symfony/http-client-contracts (v2.4.0): Extracting archive
  - Installing psr/event-dispatcher (1.0.0): Extracting archive
  - Installing symfony/event-dispatcher-contracts (v2.4.0): Extracting archive
  - Installing symfony/event-dispatcher (v5.3.0): Extracting archive
  - Installing psr/log (1.1.4): Extracting archive
  - Installing symfony/error-handler (v5.3.3): Extracting archive
  - Installing symfony/http-kernel (v5.3.3): Extracting archive
  - Installing symfony/polyfill-intl-grapheme (v1.23.0): Extracting archive
  - Installing symfony/string (v5.3.3): Extracting archive
  - Installing symfony/service-contracts (v2.4.0): Extracting archive
  - Installing symfony/console (v5.3.2): Extracting archive
  - Installing nikic/fast-route (v1.3.0): Extracting archive
  - Installing illuminate/container (v8.49.2): Extracting archive
  - Installing illuminate/pipeline (v8.49.2): Extracting archive
  - Installing illuminate/bus (v8.49.2): Extracting archive
  - Installing illuminate/events (v8.49.2): Extracting archive
  - Installing illuminate/view (v8.49.2): Extracting archive
  - Installing illuminate/translation (v8.49.2): Extracting archive
  - Installing illuminate/validation (v8.49.2): Extracting archive
  - Installing illuminate/testing (v8.49.2): Extracting archive
  - Installing symfony/process (v5.3.2): Extracting archive
  - Installing ramsey/collection (1.1.3): Extracting archive
  - Installing brick/math (0.9.2): Extracting archive
  - Installing ramsey/uuid (4.1.1): Extracting archive
  - Installing opis/closure (3.6.2): Extracting archive
  - Installing illuminate/database (v8.49.2): Extracting archive
  - Installing illuminate/console (v8.49.2): Extracting archive
  - Installing illuminate/queue (v8.49.2): Extracting archive
  - Installing illuminate/pagination (v8.49.2): Extracting archive
  - Installing monolog/monolog (2.3.0): Extracting archive
  - Installing illuminate/log (v8.49.2): Extracting archive
  - Installing illuminate/http (v8.49.2): Extracting archive
  - Installing illuminate/hashing (v8.49.2): Extracting archive
  - Installing illuminate/encryption (v8.49.2): Extracting archive
  - Installing illuminate/config (v8.49.2): Extracting archive
  - Installing illuminate/cache (v8.49.2): Extracting archive
  - Installing illuminate/broadcasting (v8.49.2): Extracting archive
  - Installing illuminate/auth (v8.49.2): Extracting archive
  - Installing webmozart/assert (1.10.0): Extracting archive
  - Installing dragonmantank/cron-expression (v3.1.0): Extracting archive
  - Installing laravel/lumen-framework (v8.2.4): Extracting archive
  - Installing hamcrest/hamcrest-php (v2.0.1): Extracting archive
  - Installing mockery/mockery (1.4.3): Extracting archive
  - Installing phpdocumentor/reflection-common (2.2.0): Extracting archive
  - Installing phpdocumentor/type-resolver (1.4.0): Extracting archive
  - Installing phpdocumentor/reflection-docblock (5.2.2): Extracting archive
  - Installing sebastian/version (3.0.2): Extracting archive
  - Installing sebastian/type (2.3.4): Extracting archive
  - Installing sebastian/resource-operations (3.0.3): Extracting archive
  - Installing sebastian/recursion-context (4.0.4): Extracting archive
  - Installing sebastian/object-reflector (2.0.4): Extracting archive
  - Installing sebastian/object-enumerator (4.0.4): Extracting archive
  - Installing sebastian/global-state (5.0.3): Extracting archive
  - Installing sebastian/exporter (4.0.3): Extracting archive
  - Installing sebastian/environment (5.1.3): Extracting archive
  - Installing sebastian/diff (4.0.4): Extracting archive
  - Installing sebastian/comparator (4.0.6): Extracting archive
  - Installing sebastian/code-unit (1.0.8): Extracting archive
  - Installing sebastian/cli-parser (1.0.1): Extracting archive
  - Installing phpunit/php-timer (5.0.3): Extracting archive
  - Installing phpunit/php-text-template (2.0.4): Extracting archive
  - Installing phpunit/php-invoker (3.1.1): Extracting archive
  - Installing phpunit/php-file-iterator (3.0.5): Extracting archive
  - Installing theseer/tokenizer (1.2.0): Extracting archive
  - Installing nikic/php-parser (v4.11.0): Extracting archive
  - Installing sebastian/lines-of-code (1.0.3): Extracting archive
  - Installing sebastian/complexity (2.0.2): Extracting archive
  - Installing sebastian/code-unit-reverse-lookup (2.0.3): Extracting archive
  - Installing phpunit/php-code-coverage (9.2.6): Extracting archive
  - Installing doctrine/instantiator (1.4.0): Extracting archive
  - Installing phpspec/prophecy (1.13.0): Extracting archive
  - Installing phar-io/version (3.1.0): Extracting archive
  - Installing phar-io/manifest (2.0.1): Extracting archive
  - Installing myclabs/deep-copy (1.10.2): Extracting archive
  - Installing phpunit/phpunit (9.5.6): Extracting archive
46 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating optimized autoload files
62 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
</pre></div>


<p>Ua vez tenemos instalado correctamente Lumen, vamos a comprobar que el proyecto se ha generado correctamente:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; highlight: [1,2]; title: ; notranslate">
~$ cd debugbar_lumen      
~$ php -S localhost:8000 -t public                                                                            
PHP 7.3.27 Development Server started at Mon Jul 12 22:36:12 2021
Listening on http://localhost:8000
Document root is /.../debugbar_lumen/public
Press Ctrl-C to quit.
</pre></div>


<h2 class="wp-block-heading">Instalación de la barra de debug</h2>



<p>Usando Composer instalamos la dependencia de DebugBar</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; highlight: [1]; title: ; notranslate">
~$ composer require barryvdh/laravel-debugbar --dev                                                           
Using version ^3.6 for barryvdh/laravel-debugbar
./composer.json has been updated
Running composer update barryvdh/laravel-debugbar
Loading composer repositories with package information
Updating dependencies
Lock file operations: 5 installs, 0 updates, 0 removals
  - Locking barryvdh/laravel-debugbar (v3.6.2)
  - Locking illuminate/routing (v8.49.2)
  - Locking maximebf/debugbar (v1.16.5)
  - Locking symfony/debug (v4.4.25)
  - Locking symfony/routing (v5.3.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 5 installs, 0 updates, 0 removals
  - Installing symfony/debug (v4.4.25): Extracting archive
  - Installing maximebf/debugbar (v1.16.5): Extracting archive
  - Installing symfony/routing (v5.3.0): Extracting archive
  - Installing illuminate/routing (v8.49.2): Extracting archive
  - Installing barryvdh/laravel-debugbar (v3.6.2): Extracting archive
7 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating optimized autoload files
65 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
</pre></div>


<p>Ahora tenemos por objetivo poder indicar cuándo queremos que se muestren los datos del Debugbar en nuestra API. Para ello modificaremos el fichero <strong><em>.env</em></strong> y el fichero <em><strong>.env.example</strong></em> (para que si alguien más instala nuestra aplicación tenga una referencia) y pondremos la variable <strong>APP_DEBUG</strong> a <strong>true</strong> y una nueva variable llamada <strong>DEBUGBAR_ENABLED</strong> que permitirá habilitar y deshabilitar la barra de debug. La barra de debug se mostrará únicamente cuando este valor sea verdadero.</p>



<p>Abrimos el fichero <strong>bootstrap/app.php</strong> y habilitamos, si <em><strong>APP_DEBUG=true</strong></em> y la petición <strong>no se está ejecutando desde consola</strong> la inyección del provider:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
if (!$app-&gt;runningInConsole() &amp;&amp; config(&#039;APP_DEBUG&#039;)) {
 $app-&gt;register(Barryvdh\Debugbar\LumenServiceProvider::class);
}
</pre></div>


<p>Esta comprobación de que ejecutamos desde consola nos permite bypasear determinados errores que puede dar debugbar en Lumen, como:</p>



<p><em>Argument 2 passed to Barryvdh\Debugbar\ServiceProvider::Barryvdh\Debugbar\{closure}() must be an instance of Illuminate\Foundation\Application, instance of Laravel\Lumen\Application given, called in ./vendor/illuminate/container/Container.php on line 763 {«exception»:»[object] (TypeError(code: 0): Argument 2 passed to Barryvdh\\Debugbar\\ServiceProvider::Barryvdh\\Debugbar\\{closure}() must be an instance of Illuminate\\Foundation\\Application, instance of Laravel\\Lumen\\Application given, called in ./vendor/illuminate/container/Container.php on line 763 at ./vendor/barryvdh/laravel-debugbar/src/ServiceProvider.php:59)</em></p>



<p>Finalmente copiaremos el fichero de configuración en la carpeta config:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
~$ mkdir config                                                                                               
~$ cp vendor/barryvdh/laravel-debugbar/config/debugbar.php config
</pre></div>


<p>Y, de nuevo, en el fichero <strong>bootstrap/app.php</strong>, realizaremos un cambio para activar este fichero de configuración. Para ello añadiremos la siguiente línea:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
$app-&gt;configure(&#039;debugbar&#039;);
</pre></div>


<p>Ha llegado el momento de comprobar que no hemos cometido ningún error. Para ello vamos a volver a levantar el servidor:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; highlight: [1]; title: ; notranslate">
~$ php -S localhost:8000 -t public                                                                            
PHP 7.3.27 Development Server started at Mon Jul 12 22:36:12 2021
Listening on http://localhost:8000
Document root is /.../debugbar_lumen/public
Press Ctrl-C to quit.
</pre></div>


<p>Y con curl o con un programa similar a <a href="https://www.postman.com/" target="_blank" rel="noreferrer noopener" title="https://www.postman.com/">Postman</a> vamos a realizar una petición al servidor:</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><a href="https://www.dipler.org/wp-content/uploads/2021/07/image.png"><img loading="lazy" decoding="async" width="1024" height="973" src="https://www.dipler.org/wp-content/uploads/2021/07/image-1024x973.png" alt="Petición básica desde POSTMAN a la API" class="wp-image-2206" srcset="https://www.dipler.org/wp-content/uploads/2021/07/image-1024x973.png 1024w, https://www.dipler.org/wp-content/uploads/2021/07/image-300x285.png 300w, https://www.dipler.org/wp-content/uploads/2021/07/image-768x730.png 768w, https://www.dipler.org/wp-content/uploads/2021/07/image-1536x1460.png 1536w, https://www.dipler.org/wp-content/uploads/2021/07/image-2048x1947.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure></div>



<p>El problema es que estamos definiendo una API y queremos que devuelva, en este caso, los datos en JSON. Por ello vamos a hacer un pequeño cambio en el fichero <strong>routes/web.php</strong>, convirtiendo:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
$router-&gt;get(&#039;/&#039;, function () use ($router) {
    return $router-&gt;app-&gt;version();
});
</pre></div>


<p>en</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
$router-&gt;get(&#039;/&#039;, function () use ($router) {
    return response()-&gt;json(&#x5B;&#039;version&#039; =&gt; $router-&gt;app-&gt;version()]);
});
</pre></div>


<p>De este modo, repitiendo la misma llamada que antes, obtendremos el siguiente valor por respuesta:</p>



<figure class="wp-block-image size-large"><a href="https://www.dipler.org/wp-content/uploads/2021/07/image-1.png"><img loading="lazy" decoding="async" width="1024" height="973" src="https://www.dipler.org/wp-content/uploads/2021/07/image-1-1024x973.png" alt="Obtención de la versión en json" class="wp-image-2207" srcset="https://www.dipler.org/wp-content/uploads/2021/07/image-1-1024x973.png 1024w, https://www.dipler.org/wp-content/uploads/2021/07/image-1-300x285.png 300w, https://www.dipler.org/wp-content/uploads/2021/07/image-1-768x730.png 768w, https://www.dipler.org/wp-content/uploads/2021/07/image-1-1536x1460.png 1536w, https://www.dipler.org/wp-content/uploads/2021/07/image-1-2048x1947.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>Si ahora habilitásemos la Debugbar, estaríamos generando una respuesta JSON inválida, así que vamos a incluir el resultado en json de respuesta. Para ello vamos a crear el fichero <strong>app/Http/Middleware/JsonDebugbar.php</strong> con el siguiente código extraído de un <a href="https://github.com/barryvdh/laravel-debugbar/issues/252" title="https://github.com/barryvdh/laravel-debugbar/issues/252" target="_blank" rel="noreferrer noopener">ticket cerrado</a> del propio proyecto:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
&lt;?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\JsonResponse;

class JsonDebugbar
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        
        if (
            $response instanceof JsonResponse &amp;&amp;
            app()-&gt;bound(&#039;debugbar&#039;) &amp;&amp;
            app(&#039;debugbar&#039;)-&gt;isEnabled() &amp;&amp;
            is_object($response-&gt;getData())
        ) {
            $response-&gt;setData($response-&gt;getData(true) + &#x5B;
                &#039;_debugbar&#039; =&gt; app(&#039;debugbar&#039;)-&gt;getData(),
            ]);
        }

        return $response;
    }
}
</pre></div>


<h3 class="wp-block-heading">a) Añadir al fichero de rutas el middleware</h3>



<p>Vamos a registrar el nuevo <a href="https://laravel.com/docs/8.x/middleware#registering-middleware" target="_blank" rel="noreferrer noopener" title="https://laravel.com/docs/8.x/middleware#registering-middleware">middleware</a> a nivel de ruta. Para hacer esto tenemos dos opciones: en el fichero <strong>bootstrap/app.php</strong> añadiendo la siguiente línea:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; highlight: [2]; title: ; notranslate">
$app-&gt;routeMiddleware(&#x5B;
    &#039;jsonDebugbar&#039; =&gt; App\Http\Middleware\JsonDebugbar::class,
// more middlewares to be declared
]);
</pre></div>


<p>Si ahora realizamos otra petición a través de postman, veremos que aun no se aplican los cambios, porque la ruta en cuestión necesita invocar al middleware.</p>



<p>Para hacer esto modificaremos el fichero <strong>routes/web.php</strong> e introduciremos el grupo que invoque al middleware:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; highlight: [1,5]; title: ; notranslate">
$router-&gt;group(&#x5B;&#039;middleware&#039; =&gt; &#039;jsonDebugbar&#039;], function () use ($router) {
    $router-&gt;get(&#039;/&#039;, function () use ($router) {
        return response()-&gt;json(&#x5B;&#039;version&#039; =&gt; $router-&gt;app-&gt;version()]);
    });
});
</pre></div>


<h3 class="wp-block-heading">b) Añadir a nivel global el middleware</h3>



<p>Para ello modificaremos el fichero <strong>bootstrap/app.php</strong> y añadiremos el <a href="https://laravel.com/docs/8.x/middleware#registering-middleware" target="_blank" rel="noreferrer noopener" title="https://laravel.com/docs/8.x/middleware#registering-middleware">middleware</a>:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
$app-&gt;middleware(&#x5B;
    App\Http\Middleware\JsonDebugbar::class
]);
</pre></div>


<h2 class="wp-block-heading">Comprobaciones</h2>



<p>Si una vez invocado el middleware realizamos una petición a través de postman, podremos observar como somos capaces de ver el detalle de la petición con:</p>



<ul class="wp-block-list"><li>Tiempos</li><li>Modelos</li><li>Queries</li><li>etc.</li></ul>



<figure class="wp-block-image size-large"><a href="https://www.dipler.org/wp-content/uploads/2021/07/image-2.png"><img loading="lazy" decoding="async" width="1024" height="650" src="https://www.dipler.org/wp-content/uploads/2021/07/image-2-1024x650.png" alt="Petición postman con el elemento del debugbar." class="wp-image-2209" srcset="https://www.dipler.org/wp-content/uploads/2021/07/image-2-1024x650.png 1024w, https://www.dipler.org/wp-content/uploads/2021/07/image-2-300x190.png 300w, https://www.dipler.org/wp-content/uploads/2021/07/image-2-768x487.png 768w, https://www.dipler.org/wp-content/uploads/2021/07/image-2-1536x974.png 1536w, https://www.dipler.org/wp-content/uploads/2021/07/image-2-2048x1299.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure><p>The post <a href="https://www.dipler.org/2021/07/instalando-y-utilizando-debugbar-en-lumen/">Instalando y utilizando Debugbar en Lumen</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.dipler.org/2021/07/instalando-y-utilizando-debugbar-en-lumen/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Dipler vuelve después de 10 años</title>
		<link>https://www.dipler.org/2021/07/estamos-de-vuelta-dipler-vuelve-despues-de-10-anos/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=estamos-de-vuelta-dipler-vuelve-despues-de-10-anos</link>
					<comments>https://www.dipler.org/2021/07/estamos-de-vuelta-dipler-vuelve-despues-de-10-anos/#respond</comments>
		
		<dc:creator><![CDATA[Alejandro Escario]]></dc:creator>
		<pubDate>Mon, 12 Jul 2021 09:54:00 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[curriculum]]></category>
		<category><![CDATA[emprendimiento]]></category>
		<category><![CDATA[historia]]></category>
		<category><![CDATA[salud]]></category>
		<guid isPermaLink="false">https://www.dipler.org/?p=2145</guid>

					<description><![CDATA[<p>Parece mentira lo rápido que pasan 10 años. En el año 2012 fue la última vez que publiqué una entrada en este blog. Por aquel entonces estaba todavía terminando la carrera y, aunque intenté reavivarlo con otro nombre en 2015, no fui capaz de sacar el tiempo suficiente. La vida<a class="moretag" href="https://www.dipler.org/2021/07/estamos-de-vuelta-dipler-vuelve-despues-de-10-anos/"> Leer más</a></p>
<p>The post <a href="https://www.dipler.org/2021/07/estamos-de-vuelta-dipler-vuelve-despues-de-10-anos/">Dipler vuelve después de 10 años</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Parece mentira lo rápido que pasan 10 años. En el año 2012 fue la última vez que publiqué una entrada en este blog. Por aquel entonces estaba todavía terminando la carrera y, aunque intenté reavivarlo con otro nombre en 2015, no fui capaz de sacar el tiempo suficiente. La vida laboral me resultó fascinante y me centré mucho en ella y en una serie de proyectos personales.</p>



<p>Estos años han sido años de grandes cambios y muy interesantes que. Espero que los próximos 5 sean como mínimo tan interesantes. No obstante considero que, de no haberme centrado en ellas, probablemente no hubiesen sucedido. Como dicen, «la suerte existe, pero tiene que pillarte trabajando».</p>



<p>En este tiempo he trabajado como: </p>



<ul class="wp-block-list"><li>autónomo (dando soporte a firmas publicitarias, creando aplicaciones, webs, consultoría, etc.) </li><li>banca por un breve periodo de tiempo</li><li>montado dos empresas de aplicaciones web/móviles (que hubo que cerrar por distintos temas)</li><li>finalmente me he especializado en el ámbito tecnológico sanitario y emprendimiento.</li></ul>



<p>Esta especialización en el ámbito sanitario (a sabiendas de que aun me queda mucho por aprender en el sector), ha sido una de las mejores decisiones que he tomado en este periodo de tiempo. Ésta ha venido impulsada especialmente por dos proyectos muy interesantes y de los que espero ir contando novedades próximamente:</p>



<h2 class="wp-block-heading">In3</h2>



<p><a href="https://in3ator.org" target="_blank" rel="noreferrer noopener">In3ator</a> es un proyecto nacido a raíz del <a href="http://fabacademy.org/archives/2015/eu/students/escario_mendez.alejandro/index.html" target="_blank" rel="noreferrer noopener">FabAcademy2015</a> (USP CEU) y el Master de Ingeniería Biomédica que cursé en 2014-2015.</p>



<p>El proyecto consiste en diseñar y fabricar una incubadora neonatal de bajo coste <strong>fiable, accesible, reparable y replicable</strong> en cualquier lugar del mundo. Os dejo una pequeña presentación por si queréis echarle un vistazo al proyecto.</p>



<iframe loading="lazy" src="//www.slideshare.net/slideshow/embed_code/key/BlQWaaIEHxSbC2" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen=""> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/AlejandroEscario/in3-una-incubadora-de-bajo-coste" title="In3: una incubadora de bajo coste" target="_blank" rel="noopener">In3: una incubadora de bajo coste</a> </strong> de <strong><a href="https://www.slideshare.net/AlejandroEscario" target="_blank" rel="noopener">Alejandro Escario</a></strong> </div>



<p>Este proyecto que comenzó como un mero proyecto académico evolucionó en la creación de una asociación llamada <a href="https://medicalopenworld.org" target="_blank" rel="noreferrer noopener">Medical Open World</a>. Permitiendo al proyecto obtener premios:</p>



<ul class="wp-block-list"><li>Forbes 30 under 30</li><li>MIT Technology Review «Innovators under 35»</li><li>etc.</li></ul>



<p>y ser invitado a dar charlas y congresos:</p>



<ul class="wp-block-list"><li>Stanford Medicine X 2015</li><li>World Congress of Perinatal Medicine</li><li>Participación en cursos y másteres</li></ul>



<p>No obstante, lo más bonito y destacable del proyecto es aportar un granito de arena para ayudar a aquellos que lo necesiten. </p>



<figure class="wp-block-image size-large"><a href="https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-07-a-las-23.47.14.png"><img loading="lazy" decoding="async" width="1024" height="638" src="https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-07-a-las-23.47.14-1024x638.png" alt="" class="wp-image-2153" srcset="https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-07-a-las-23.47.14-1024x638.png 1024w, https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-07-a-las-23.47.14-300x187.png 300w, https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-07-a-las-23.47.14-768x479.png 768w, https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-Pantalla-2021-07-07-a-las-23.47.14.png 1360w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>Incubadora</figcaption></figure>



<p>Este proyecto nació en 2015 como un proyecto humilde y con pocas pretensiones y, a día de hoy, 5 años después, puedo decir que, ninguno de los voluntarios involucrados en el mismo nos pudimos imaginar al punto al que hemos llegado.</p>



<h2 class="wp-block-heading">Madrija</h2>



<p>El otro gran proyecto en el que me embarqué hace ya 5 años es el de <a href="https://www.madrija.com" target="_blank" rel="noreferrer noopener">Madrija</a>, una empresa toledana de recién creación que aspiraba a buscarse un hueco en el sector salud. Unos años después ya somos más de 30 personas. Y, no sin una gran cantidad de esfuerzo entre medias, se puede decir que estamos consiguiendo posicionarnos en el sector. Principalmente en el ámbito de la cardiología y del I+D+i.</p><p>The post <a href="https://www.dipler.org/2021/07/estamos-de-vuelta-dipler-vuelve-despues-de-10-anos/">Dipler vuelve después de 10 años</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.dipler.org/2021/07/estamos-de-vuelta-dipler-vuelve-despues-de-10-anos/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Ordenar tablas sin usar macros [Excel]</title>
		<link>https://www.dipler.org/2015/01/ordenar-tablas-sin-usar-macros-excel/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=ordenar-tablas-sin-usar-macros-excel</link>
					<comments>https://www.dipler.org/2015/01/ordenar-tablas-sin-usar-macros-excel/#respond</comments>
		
		<dc:creator><![CDATA[Alejandro Escario]]></dc:creator>
		<pubDate>Fri, 30 Jan 2015 21:38:00 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://www.dipler.org/?p=2137</guid>

					<description><![CDATA[<p>Últimamente me paso muchas horas delante del Excel por temas de trabajo y me he dado cuenta de que, a pesar de ser una herramienta muy potente pocos saben utilizarla bien de verdad. Yo, por desgracia no me encuentro entre ellos. El secreto de la productividad utilizando en esta herramienta<a class="moretag" href="https://www.dipler.org/2015/01/ordenar-tablas-sin-usar-macros-excel/"> Leer más</a></p>
<p>The post <a href="https://www.dipler.org/2015/01/ordenar-tablas-sin-usar-macros-excel/">Ordenar tablas sin usar macros [Excel]</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Últimamente me paso muchas horas delante del Excel por temas de trabajo y me he dado cuenta de que, a pesar de ser una herramienta muy potente pocos saben utilizarla bien de verdad. Yo, por desgracia no me encuentro entre ellos.</p>



<p>El secreto de la productividad utilizando en esta herramienta no es otra que conseguir maximizar la automatización de tareas. Por ello voy a intentar describir paso a paso como <strong>ordenar una lista</strong> sin tener que hacer ni un solo clic.</p>



<p>Si bien es cierto que esto se puede hacer “fácilmente” haciendo uso de una macro, vamos a ver los pasos a seguir para hacer lo mismo mezclando dos funciones de Excel: <strong>RANK</strong> y <strong>VLOOKUP</strong>.</p>



<span id="more-2137"></span>



<div class="wp-block-image"><figure class="aligncenter size-large"><a href="https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-pantalla-2015-01-30-a-las-0.47.37.png"><img loading="lazy" decoding="async" width="1024" height="661" src="https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-pantalla-2015-01-30-a-las-0.47.37-1024x661.png" alt="Prima de riesgo" class="wp-image-2138" srcset="https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-pantalla-2015-01-30-a-las-0.47.37-1024x661.png 1024w, https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-pantalla-2015-01-30-a-las-0.47.37-300x194.png 300w, https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-pantalla-2015-01-30-a-las-0.47.37-768x496.png 768w, https://www.dipler.org/wp-content/uploads/2021/07/Captura-de-pantalla-2015-01-30-a-las-0.47.37.png 1414w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>Datos Prima de Riesgo [mayo 2014]</figcaption></figure></div>



<p>En primer lugar vamos a crear una tabla con información, por ejemplo los valores de la <a href="http://www.datosmacro.com/prima-riesgo" target="_blank" rel="noreferrer noopener">prima de riesgo</a> de distintos países frente a Alemania (datos del 19 de mayo de 2014):</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>País</strong></td><td><strong>Prima de Riesgo</strong></td></tr><tr><td><strong>España</strong></td><td>&nbsp; &nbsp; 164,00</td></tr><tr><td><strong>Reino Unido</strong></td><td>&nbsp; &nbsp; 123,00</td></tr><tr><td><strong>Francia</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 46,00</td></tr><tr><td><strong>Italia</strong></td><td>&nbsp; &nbsp; 175,00</td></tr><tr><td><strong>Portugal</strong></td><td>&nbsp; &nbsp; 238,00</td></tr><tr><td><strong>Estados Unidos</strong></td><td>&nbsp; &nbsp; 119,00</td></tr><tr><td><strong>Suiza</strong></td><td>&#8211;&nbsp;&nbsp; &nbsp; &nbsp; 59,00</td></tr><tr><td><strong>Japón</strong></td><td>&#8211;&nbsp;&nbsp; &nbsp; &nbsp; 74,00</td></tr><tr><td><strong>Australia</strong></td><td>&nbsp; &nbsp; 237,00</td></tr><tr><td><strong>Austria</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 23,00</td></tr><tr><td><strong>Finlandia</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 31,00</td></tr><tr><td><strong>Grecia</strong></td><td>&nbsp; &nbsp; 538,00</td></tr><tr><td><strong>Holanda</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 31,00</td></tr><tr><td><strong>India</strong></td><td>&nbsp; &nbsp; 751,00</td></tr><tr><td><strong>Irlanda</strong></td><td>&nbsp; &nbsp; 132,00</td></tr><tr><td><strong>Nueva Zelanda</strong></td><td>&nbsp; &nbsp; 297,00</td></tr><tr><td><strong>Suecia</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 49,00</td></tr><tr><td><strong>Canadá</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 93,00</td></tr></tbody></table></figure>



<p>Ahora vamos a establecer el ranking de cada país teniendo en cuenta su prima de riesgo. Para ello, en la columna de la izquierda (es importante que sea en la de la izquierda, ya que posteriormente utilizaremos la función VLOOKUP) de la primera fila escribiremos la siguiente fórmula:</p>



<pre class="wp-block-preformatted">=RANK.EQ(G7;$G$7:$G$24;1)</pre>



<p><strong>RANK.EQ</strong> es una función que nos dará el orden de un valor dentro de un listado de valores. La coletilla <strong>EQ</strong> hará que en caso de empate se muestre el mismo número dos veces; en este caso Finlandia y Holanda tienen la misma Prima de Riesgo y están en cuarto lugar, por lo que asignará a ambas el valor de empate a 4 (En caso de querer ver la media de los valores de la posición, en este caso 4,5 en lugar de 4, deberemos hacer uso de <strong>RANK.AVG</strong>). Este empate más adelante tendremos que resolverlo para poder ordenar correctamente la lista.</p>



<p>Para la función <strong>RANK.EQ</strong>:</p>



<ul class="wp-block-list"><li>El primer parámetro (G7) hace referencia al valor para el que deseamos buscar una posición.</li><li>El segundo parámetro ($G$7:$G$24) indica el vector sobre el que se hará la clasificación de los valores. En este caso después de seleccionar la columna G entre la fila 7 y la 24, hemos añadido los símbolos $ (pulsando f4) para que al arrastrar la fórmula a otras filas, no cambie el vector sobre el que se va a buscar la posición.</li><li>El tercer valor determina que el orden que se quiere seguir es ascendente. Si hubiésemos escrito un 0, entonces sería descendente.</li></ul>



<p>Finalmente, para obtener las posiciones asociadas a todos los valores aplicamos la fórmula a cada fila.</p>



<p>Tras completar estos pasos, nuestra tabla debería ser parecida a la siguiente:</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>Ranking</strong></td><td><strong>País</strong></td><td><strong>Prima de Riesgo</strong></td></tr><tr><td><strong>12</strong></td><td><strong>España</strong></td><td>&nbsp; &nbsp; 164,00</td></tr><tr><td><strong>10</strong></td><td><strong>Reino Unido</strong></td><td>&nbsp; &nbsp; 123,00</td></tr><tr><td><strong>6</strong></td><td><strong>Francia</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 46,00</td></tr><tr><td><strong>13</strong></td><td><strong>Italia</strong></td><td>&nbsp; &nbsp; 175,00</td></tr><tr><td><strong>15</strong></td><td><strong>Portugal</strong></td><td>&nbsp; &nbsp; 238,00</td></tr><tr><td><strong>9</strong></td><td><strong>Estados Unidos</strong></td><td>&nbsp; &nbsp; 119,00</td></tr><tr><td><strong>2</strong></td><td><strong>Suiza</strong></td><td>&#8211; &nbsp; &nbsp; 59,00</td></tr><tr><td><strong>1</strong></td><td><strong>Japón</strong></td><td>&#8211; &nbsp; &nbsp; 74,00</td></tr><tr><td><strong>14</strong></td><td><strong>Australia</strong></td><td>&nbsp; &nbsp; 237,00</td></tr><tr><td><strong>3</strong></td><td><strong>Austria</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 23,00</td></tr><tr><td><strong>4</strong></td><td><strong>Finlandia</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 31,00</td></tr><tr><td><strong>17</strong></td><td><strong>Grecia</strong></td><td>&nbsp; &nbsp; 538,00</td></tr><tr><td><strong>4</strong></td><td><strong>Holanda</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 31,00</td></tr><tr><td><strong>18</strong></td><td><strong>India</strong></td><td>&nbsp; &nbsp; 751,00</td></tr><tr><td><strong>11</strong></td><td><strong>Irlanda</strong></td><td>&nbsp; &nbsp; 132,00</td></tr><tr><td><strong>16</strong></td><td><strong>Nueva Zelanda</strong></td><td>&nbsp; &nbsp; 297,00</td></tr><tr><td><strong>7</strong></td><td><strong>Suecia</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 49,00</td></tr><tr><td><strong>8</strong></td><td><strong>Canadá</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 93,00</td></tr></tbody></table></figure>



<p>Ahora sólo nos queda ordenar la tabla. Para lo que haremos uso de la función <strong>VLOOKUP</strong>.</p>



<p>Para ello, lo primero que vamos a hacer es escribir en la columna de la izquierda de nuestra nueva tabla el orden en el que deseamos que aparezca nuestra tabla. En nuestro caso vamos a ordenarlo en orden ascendente, por lo que en la primera columna deberemos escribir una enumeración de 1 a 18, marcando así cada una de las filas.</p>



<p>Para cada fila escribiremos en la columna contigua a la enumeración:</p>



<pre class="wp-block-preformatted">=VLOOKUP($I7;$E$7:$G$24;2;FALSE)</pre>



<p>De manera que:</p>



<ul class="wp-block-list"><li>El primer parámetro indica la columna en la que indicamos el valor que deseamos buscar, en nuestro caso la enumeración.</li><li>En el segundo parámetro indicamos la tabla para la cual:<ul><li>En la primera columna de la misma se buscará el valor que hemos indicado en el primer parámetro.</li><li>En el resto de columnas tenemos información que queramos extraer de la tabla una vez encontrado el valor a buscar.</li></ul></li><li>Como tercer parámetro indicamos que una vez encontrado ese valor, mostraremos en la celda el valor de la segunda columna.</li><li>Finalmente, el cuarto parámetro indica que se desea encontrar el valor buscado coincida exactamente con el valor que deseamos buscar.</li></ul>



<p>Repetimos el proceso con la tercera columna para tener el valor de la prima de riesgo asociada al país y listo. Ya tenemos nuestra lista ordenada.</p>



<p>Si no tenemos valores repetidos, ya hemos terminado, pero este no es nuestro caso, nos vamos a encontrar con errores al aplicarle a la tabla la función <strong>VLOOKUP</strong> porque tenemos dos países con la misma prima de Riesgo.</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>Ranking</strong></td><td><strong>País</strong></td><td><strong>Prima de Riesgo</strong></td></tr><tr><td><strong>1</strong></td><td><strong>Japón</strong></td><td>&#8211; &nbsp; &nbsp; 74,00</td></tr><tr><td><strong>2</strong></td><td><strong>Suiza</strong></td><td>&#8211; &nbsp; &nbsp; 59,00</td></tr><tr><td><strong>3</strong></td><td><strong>Austria</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 23,00</td></tr><tr><td><strong>4</strong></td><td><strong>Finlandia</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 31,00</td></tr><tr><td><strong>5</strong></td><td><strong>#N/A</strong></td><td>#N/A</td></tr><tr><td><strong>6</strong></td><td><strong>Francia</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 46,00</td></tr><tr><td><strong>7</strong></td><td><strong>Suecia</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 49,00</td></tr><tr><td><strong>8</strong></td><td><strong>Canadá</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 93,00</td></tr><tr><td><strong>9</strong></td><td><strong>Estados Unidos</strong></td><td>&nbsp; &nbsp; 119,00</td></tr><tr><td><strong>10</strong></td><td><strong>Reino Unido</strong></td><td>&nbsp; &nbsp; 123,00</td></tr><tr><td><strong>11</strong></td><td><strong>Irlanda</strong></td><td>&nbsp; &nbsp; 132,00</td></tr><tr><td><strong>12</strong></td><td><strong>España</strong></td><td>&nbsp; &nbsp; 164,00</td></tr><tr><td><strong>13</strong></td><td><strong>Italia</strong></td><td>&nbsp; &nbsp; 175,00</td></tr><tr><td><strong>14</strong></td><td><strong>Australia</strong></td><td>&nbsp; &nbsp; 237,00</td></tr><tr><td><strong>15</strong></td><td><strong>Portugal</strong></td><td>&nbsp; &nbsp; 238,00</td></tr><tr><td><strong>16</strong></td><td><strong>Nueva Zelanda</strong></td><td>&nbsp; &nbsp; 297,00</td></tr><tr><td><strong>17</strong></td><td><strong>Grecia</strong></td><td>&nbsp; &nbsp; 538,00</td></tr><tr><td><strong>18</strong></td><td><strong>India</strong></td><td>&nbsp; &nbsp; 751,00</td></tr></tbody></table></figure>



<p>Llegados a este punto tenemos varias opciones:</p>



<ul class="wp-block-list"><li>Arreglar el error a mano: en este caso tenemos pocos registros por lo que no debería suponer un problema corregir el registro que nos falta.</li><li>Modificar los datos originales de tal modo que no afecten a los datos que mostramos en la hoja pero que evite los empates.</li></ul>



<p>Vamos a proceder a explicar el segundo método aun a sabiendas de que no siempre será posible seguir estos pasos antes de aplicar la función <strong>RANK.EQ</strong>.</p>



<p><em><strong>*NOTA:</strong></em>&nbsp;lo que voy a contar a continuación podría calificarse de chapuza (útil y resolutiva, eso sí). Es posible que existan otras formas mejores de hacerlo sin usar macros.</p>



<ol class="wp-block-list"><li>Observar la precisión de los datos. En este caso, estamos tratando con la prima de riesgo, que son valores enteros, es decir, en este caso tenemos una precisión de unidades, pero en la tabla queremos mostrar hasta las centésimas.</li><li>Contamos con 18 registros que queremos mostrar ordenados, es decir, necesitamos dos dígitos.</li><li>Es decir:<ul><li>2 decimales =&gt; 10<sup>2</sup></li><li>2 dígitos representan el número de elementos =&gt; 10<sup>2</sup></li></ul></li><li>Ahora ponderamos cada uno de los países dándoles un orden manualmente para que, en caso de empate se haga uso de éste.</li><li>Modificamos el valor de la prima de riesgo de tal forma que quede aumentado su valor en 0,0001 veces el valor que le hemos asignado manualmente. Por ejemplo:</li></ol>



<pre class="wp-block-preformatted">=C7+0,0001*E7</pre>



<p>De este modo, deberíamos obtener un resultado final satisfactorio como el que se puede observar en la siguiente tabla:</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>Ranking</strong></td><td><strong>País</strong></td><td><strong>Prima de Riesgo</strong></td></tr><tr><td><strong>1</strong></td><td><strong>Japón</strong></td><td>&#8211; &nbsp; &nbsp; 74,00</td></tr><tr><td><strong>2</strong></td><td><strong>Suiza</strong></td><td>&#8211; &nbsp; &nbsp; 59,00</td></tr><tr><td><strong>3</strong></td><td><strong>Austria</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 23,00</td></tr><tr><td><strong>4</strong></td><td><strong>Finlandia</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 31,00</td></tr><tr><td><strong>5</strong></td><td><strong>Holanda</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 31,00</td></tr><tr><td><strong>6</strong></td><td><strong>Francia</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 46,00</td></tr><tr><td><strong>7</strong></td><td><strong>Suecia</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 49,00</td></tr><tr><td><strong>8</strong></td><td><strong>Canadá</strong></td><td>&nbsp;&nbsp; &nbsp; &nbsp; 93,00</td></tr><tr><td><strong>9</strong></td><td><strong>Estados Unidos</strong></td><td>&nbsp; &nbsp; 119,00</td></tr><tr><td><strong>10</strong></td><td><strong>Reino Unido</strong></td><td>&nbsp; &nbsp; 123,00</td></tr><tr><td><strong>11</strong></td><td><strong>Irlanda</strong></td><td>&nbsp; &nbsp; 132,00</td></tr><tr><td><strong>12</strong></td><td><strong>España</strong></td><td>&nbsp; &nbsp; 164,00</td></tr><tr><td><strong>13</strong></td><td><strong>Italia</strong></td><td>&nbsp; &nbsp; 175,00</td></tr><tr><td><strong>14</strong></td><td><strong>Australia</strong></td><td>&nbsp; &nbsp; 237,00</td></tr><tr><td><strong>15</strong></td><td><strong>Portugal</strong></td><td>&nbsp; &nbsp; 238,00</td></tr><tr><td><strong>16</strong></td><td><strong>Nueva Zelanda</strong></td><td>&nbsp; &nbsp; 297,00</td></tr><tr><td><strong>17</strong></td><td><strong>Grecia</strong></td><td>&nbsp; &nbsp; 538,00</td></tr><tr><td><strong>18</strong></td><td><strong>India</strong></td><td>&nbsp; &nbsp; 751,00</td></tr></tbody></table></figure>



<p>Finalmente, podéis descargar el archivo Excel que se ha utilizado para realizar este artículo.</p>


<a  data-e-Disable-Page-Transition="true" class="download-link" title="Versión 1.0.0" href="https://www.dipler.org/download/2133/?tmstv=1775265104" rel="nofollow" id="download-link-2133" data-redirect="false" >
	Ordenado automático de registros.xslx	(1033 descargas	)
</a><p>The post <a href="https://www.dipler.org/2015/01/ordenar-tablas-sin-usar-macros-excel/">Ordenar tablas sin usar macros [Excel]</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.dipler.org/2015/01/ordenar-tablas-sin-usar-macros-excel/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[PHP &#038; MySQL] Tratar correctamente los acentos y demás</title>
		<link>https://www.dipler.org/2012/09/php-mysql-tratar-correctamente-los-acentos-demas/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=php-mysql-tratar-correctamente-los-acentos-demas</link>
					<comments>https://www.dipler.org/2012/09/php-mysql-tratar-correctamente-los-acentos-demas/#comments</comments>
		
		<dc:creator><![CDATA[Alejandro Escario]]></dc:creator>
		<pubDate>Thu, 27 Sep 2012 09:35:30 +0000</pubDate>
				<category><![CDATA[Manuales]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">http://www.dipler.org/?p=2048</guid>

					<description><![CDATA[<p>No es la primera ni será la última vez que yo o gente que conozca, tenga problemas con los acentos en aplicaciones web que usen tecnologías PHP y MySQL. Realmente solucionar este problema no es tan complicado y, por ello, vamos a intentar abordar dos soluciones que se pueden usar<a class="moretag" href="https://www.dipler.org/2012/09/php-mysql-tratar-correctamente-los-acentos-demas/"> Leer más</a></p>
<p>The post <a href="https://www.dipler.org/2012/09/php-mysql-tratar-correctamente-los-acentos-demas/">[PHP & MySQL] Tratar correctamente los acentos y demás</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>No es la primera ni será la última vez que yo o gente que conozca, tenga problemas con los acentos en aplicaciones web que usen tecnologías <a href="http://www.php.net" target="_blank" rel="noopener noreferrer">PHP</a> y <a href="http://www.mysql.com" target="_blank" rel="noopener noreferrer">MySQL</a>. Realmente solucionar este problema no es tan complicado y, por ello, vamos a intentar abordar dos soluciones que se pueden usar por separado o unidas según nuestras necesidades.</p>
<p>Pero antes de proponer cada una de las soluciones por separado, vamos a ver un ejemplo de lo que estamos hablando: Supongamos que en nuestra página web hay un campo de entrada de datos, y en ella el usuario escribe:</p>
<blockquote><p>Café Roma</p></blockquote>
<p>Acto seguido pulsa el botón «Aceptar» para guardar ese texto en la base de datos. Todo parece ir bien, pero al recuperarlo de la base de datos y mostrarlo por pantalla vemos que escribe algo parecido a lo siguiente:</p>
<blockquote><p>CafÃ© Roma</p></blockquote>
<p>O, incluso</p>
<blockquote><p>Caf� Roma</p></blockquote>
<p>A grosso modo, esto ocurre porque estamos mezclando codificaciones uno o más sitios (navegador del usuario, servidor Apache con PHP instalado y la base de datos MySQL). Esto es un problema muy común y del que, mucha gente pregunta en foros todos los días y, por ello vamos a proponer soluciones para, en un principio mostrarlo en un navegador de forma correcta.</p>
<h1>Conversión a caracteres HTML</h1>
<p>HTML tiene una serie de caracteres especiales y reservados que tienen una función especial, un claro ejemplo son los caracteres mayor <strong>&gt;</strong> y menor <strong>&lt;</strong>, ya que, por ejemplo, estos caracteres se utilizan para delimitar las etiquetas XML en las que está basada la especificación HTML. Por ello, HTML especifica una serie de códigos llamados «Entidades HTML» que nos permiten codificar estos caracteres especiales. Por ello si queremos poner el símbolo &lt;, realmente deberíamos escribir <strong>&amp;lt;</strong> o bien&nbsp;<strong>&amp;#60;</strong>. En el primer caso estaríamos indicando ese carácter usando un código alfanumérico y, en el segundo, estamos indicando el valor de dicho carácter en ASCII.</p>
<p>Como hacer esta conversión manualmente no siempre es posible y, en el caso de que si que lo sea, es bastante tedioso escribir usando esos códigos, PHP nos brinda una función que hará el trabajo sucio por nosotros:&nbsp;<strong><a title="htmlentities" href="http://php.net/manual/es/function.htmlentities.php" target="_blank" rel="noopener noreferrer">htmlentities</a></strong><a title="htmlentities" href="http://php.net/manual/es/function.htmlentities.php" target="_blank" rel="noopener noreferrer"></a>; de manera que con invocar la función:</p>
<pre class="brush: php; title: ; notranslate">$str = htmlentities($str);</pre>
<p>De manera que ahora en nuestra variable $str en lugar de tener, por ejemplo, «Camión», que podría darnos problemas al guardarlo en una base de datos si el sistema está mal configurado (más adelante veremos como configurarlo bien), tendríamos una variable que contiene «Cami&amp;oacute;n», es decir, un string compuesto únicamente por caracteres ASCII que no debería darnos problema a la hora de persistirlo en cualquier base de datos; tenga el cotejamiento que tenga.</p>
<p>Finalmente, si vamos a mostrar el código por pantalla, tenemos dos opciones:</p>
<ol>
<li>Si vamos a mostrarlo en una web, no hace falta que tratemos el string para volver al formato original, ya que los navegadores son capaces de interpretar estos «caracteres codificados».</li>
<li>En caso de que no se coloque dentro de un fichero con formato (X)HTML, nos bastará con llamar al método <a href="http://php.net/manual/es/function.html-entity-decode.php" target="_blank" rel="noopener noreferrer">html_entities_decode</a>.</li>
</ol>
<h1>Almacenamiento directo</h1>
<p>Lo que hemos visto en el apartado anterior, no deja de ser una chapuza (para la mayor parte de los casos) y que se puede solucionar de una forma bastante sencilla y, es que, si configuramos bien nuestro servidor Apache con PHP, nuestra base de datos MySQL y la conexión entre ambas, podemos ahorrarnos todo este tratamiento de datos; y no solo eso, sino que además, nos permitirá consultar cómodamente los datos almacenados desde cualquier otro sistema sin tener que perocuparnos de deshacer la codificación de caracteres extraños.</p>
<p>Vamos a ver los pasos para realizar esta configuración directamente:</p>
<ul>
<li>El cotejamiento de la tabla (el de la base de datos también debería estarlo), debería de estar configurado en utf8, en mi caso, voy a utilizar <strong>utf8_unicode_ci</strong>. Esto podemos configurarlo, si usamos <a href="http://www.phpmyadmin.net/" target="_blank" rel="noopener noreferrer">phpmyadmin</a>, desde las opciones de la tabla.</li>
</ul>
<p><a href="https://www.dipler.org/wp-content/uploads/2012/09/Captura-de-pantalla-2012-09-27-a-las-11.24.21.png"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-2052" title="utf8 mysql cotejamiento" src="https://www.dipler.org/wp-content/uploads/2012/09/Captura-de-pantalla-2012-09-27-a-las-11.24.21.png" alt="" width="113" height="67"></a></p>
<ul>
<li>Apache (con PHP instalado) y MySQL son dos servidores completamente separados y que, no tienen por qué usar el mismo idioma, de hecho, a no ser que tengamos instalado en PHP el conector de MySQL, no seremos capaces de comunicarnos entre ambos servidores. Por ello, es interesante configurar la conexión, en este caso, el&nbsp;<em>idioma</em> en el que van a hablar; para ello, tenemos que decirle a MySQL que queremos todos los campos en UTF-8 ejecutando la siguiente query:</li>
</ul>
<div>
<pre class="brush: sql; title: ; notranslate"> SET NAMES 'utf8'&amp;amp;nbsp;</pre>
</div>
<ul>
<li>En caso de querer mostrar los datos en un fichero (X)HTML, deberíamos indicar el cotejamiento de la página añadiendo la siguiente etiqueta <strong>&lt;meta&gt;</strong> en el header de la página.</li>
</ul>
<pre class="brush: xml; title: ; notranslate">&amp;amp;nbsp;&amp;amp;lt;meta http-equiv=&amp;quot;Content-type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;amp;gt;&amp;amp;nbsp;</pre><p>The post <a href="https://www.dipler.org/2012/09/php-mysql-tratar-correctamente-los-acentos-demas/">[PHP & MySQL] Tratar correctamente los acentos y demás</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.dipler.org/2012/09/php-mysql-tratar-correctamente-los-acentos-demas/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Importar los datos de un archivo CSV &#8211; Matlab</title>
		<link>https://www.dipler.org/2012/08/importar-los-datos-de-archivo-csv-matlab/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=importar-los-datos-de-archivo-csv-matlab</link>
					<comments>https://www.dipler.org/2012/08/importar-los-datos-de-archivo-csv-matlab/#comments</comments>
		
		<dc:creator><![CDATA[Alejandro Escario]]></dc:creator>
		<pubDate>Wed, 01 Aug 2012 14:19:43 +0000</pubDate>
				<category><![CDATA[Manuales]]></category>
		<category><![CDATA[MATLAB]]></category>
		<category><![CDATA[CSV]]></category>
		<guid isPermaLink="false">http://www.dipler.org/?p=2044</guid>

					<description><![CDATA[<p>MATLAB es una herramienta estupenda para tratar con grandes cantidades de datos de manera sencilla y, por eso mismo, es utilizado para desarrollar los algoritmos deseados (como por ejemplo uno de detección de pasos) antes de implementarlos en el dispositivo final. De esta manera eliminamos el factor humano al implementar<a class="moretag" href="https://www.dipler.org/2012/08/importar-los-datos-de-archivo-csv-matlab/"> Leer más</a></p>
<p>The post <a href="https://www.dipler.org/2012/08/importar-los-datos-de-archivo-csv-matlab/">Importar los datos de un archivo CSV – Matlab</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><a href="https://www.dipler.org/wp-content/uploads/2012/08/IMG_2422.jpg"><img loading="lazy" decoding="async" class="aligncenter size-medium wp-image-2045" title="CSV" src="https://www.dipler.org/wp-content/uploads/2012/08/IMG_2422-300x225.jpg" alt="" width="300" height="225" srcset="https://www.dipler.org/wp-content/uploads/2012/08/IMG_2422-300x225.jpg 300w, https://www.dipler.org/wp-content/uploads/2012/08/IMG_2422-1024x768.jpg 1024w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>MATLAB es una herramienta estupenda para tratar con grandes cantidades de datos de manera sencilla y, por eso mismo, es utilizado para desarrollar los algoritmos deseados (como por ejemplo uno de detección de pasos) antes de implementarlos en el dispositivo final. De esta manera eliminamos el factor humano al implementar algunas funciones que vienen de serie en MATLAB como, por ejemplo, una FFT (Fast Fourier Transform).</p>
<p>El primer paso para hacer esto es importar los datos en RAW (en crudo). Estos datos estarán formateados de una u otra manera que puede depender de nosotros o no. En mi caso, estoy trabajando con un formato CSV que separa cada uno de las «columnas» con un punto y coma (semicolon) en lugar de una coma; esto hace que no pueda hacer uso fácilmente de la función por defecto de MATLAB para abrir este tipo de archivos.</p>
<p>Por ello, vamos a aprender como importar datos en un formato cualquiera dado siempre que este simule a una tabla:</p>
<pre class="brush: matlabkey; title: ; notranslate">
path = './pruebas/Sensor_record_20120731_214243_AndroSensor.csv';
formats = '%f%f%f%f%f%f%f%f%f%f';
headerLines = 1;
delimiter = ';';
&#x5B;M{1:10}] = textread(path, formats,'headerlines', headerLines, 'delimiter', delimiter);
</pre>
<p>En la primera línea indicamos la ruta en la que almacenamos nuestros datos, en la segunda indicamos el formato de cada uno de los campo; en este caso estamos indicando que tenemos 10 campos y que todos ellos son un número decimal. En la tercera línea indicamos que tenemos una línea de cabecera y que ha de saltarse, esto es especialmente interesante cuando las primeras líneas no siguen el formato del resto del fichero CSV o si, simplemente, queremos obviar esas lineas y no importarlas. En la cuarta indicamos nuestro delimitados. Y, finalmente, en la sexta, le decimos que nos meta en un CellArray de 10 posiciones los datos de dicho archivo., de manera que trabajar con los datos de la primera columna es algo tan sencillo como:</p>
<pre class="brush: matlabkey; title: ; notranslate">

plot(M{1});

</pre><p>The post <a href="https://www.dipler.org/2012/08/importar-los-datos-de-archivo-csv-matlab/">Importar los datos de un archivo CSV – Matlab</a> first appeared on <a href="https://www.dipler.org">Dipler</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.dipler.org/2012/08/importar-los-datos-de-archivo-csv-matlab/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>
