Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)

sábado, 18 de abril de 2015

Calculando los números de la serie Fibonacci de forma recursiva en Python 2.7

Una función que calcule los números de Fibonacci es el ejemplo clásico para aprender recursividad:

def fibs(x):
    if x <= 1:
        return x
    return fibs(x - 1) + fibs(x - 2)



Lo malo de esta función es que calcula un número de la serie Fibonacci específico, no calcula toda la serie hasta una cantidad determinada.

La siguiente función sí devuelve la lista de los números de Fibonacci hasta la cantidad de elementos en la lista que se le indique:

def fibList (x, limit):
    if len(x) < 2:
        return fibList([1, 2], limit)

    if len(x) > limit:
        return x

    h = x[-1] + x[-2]
    x.append(h)
    return fibList(x, limit)


La forma de llamarla es:

x = fibList([], 10)

for c in x:
    print(c)



El primer parámetro puede ser una lista vacía o los primeros valores de la serie:

x = fibList([1, 2], 10)

En ambos casos el resultado es:




La lista tiene 11 valores en lugar de 10 debido a que primero inserta el elemento con la función append y después evalúa el tamaño de la lista.

sábado, 11 de abril de 2015

Listar los archivo en una carpeta y sus subcarpetas de forma recursiva

Un día necesité listar los archivos existentes en una carpeta y sus subcarpetas. Como reto, quise implementar mi propia función y aquí está :D

Los algoritmos que recorrer árboles de directorios son recursivos, no se usan bucles debido a que el algoritmo ignora la profundidad que alcanzarán los subdirectorios en el árbol.

import os
from os import listdir
from os.path import isfile, isdir, join

def listdir_recurd(files_list, root, folder, checked_folders):

    if (folder != root):
        checked_folders.append(folder)

    for f in listdir(folder):

        d = join(folder, f)       

        if isdir(d) and d not in checked_folders:
            listdir_recurd(files_list, root, d, checked_folders)
        else:
            if isfile(d):  # si no hago esto, inserta en la lista el nombre de las carpetas ignoradas
                files_list.append(f)

    return files_list



La forma de usar esta función es:

if __name__ == "__main__":
    filez = listdir_recurd([], 'D:\Sample', 'D:\Sample', ['D:\\Sample\\Uno']) # esto omite la subcarpeta 'D:\\Sample\\Uno'

    filez = listdir_recurd([], 'D:\Sample', 'D:\Sample', ['D:\\Sample\\Uno', 'D:\\Sample\\Dos']) # esto omite la subcarpeta 'D:\\Sample\\Uno' y la subcarpeta 'D:\\Sample\\Dos'

    filez_ = listdir_recurd([], 'D:\Sample3', 'D:\Sample3', []) # esto no omite ninguna subcarpeta

La función recibe los siguientes parámetros:

"files_list": es el acumulador. Siempre es una lista vacía.

"root" y "folder": carpeta raíz y carpeta con los archivos que se va a listar, estas dos rutas deben ser la misma. La carpeta con los archivos a listar es la carpeta actual cuyos archivos se están listando, su valor lo controla el algoritmo y va recorriendo las subcarpetas que se van hallando.

"checked_folders": lista las subcarpetas en la carpeta del parámetro "root" que se desean omitir. Si se desea listar todos los archivos, se ingresa una lista vacía.

Python permite ingresar el separador de rutas como \ ó \\.

Esta función sólo ha sido probada en Windows, y ejecutada con Python Tool for Visual Studio usando Python 2.7

lunes, 30 de marzo de 2015

Recorrer todos los controles en un contenedor: .Net y Java Swing

En este ejemplo, se quiere habilitar los controles de un contenedor en función al valor de selección de un checkbox.

En el caso de Java, el contenedor es un jPanel:

En Java 7:

for (Component c : jPanel1.getComponents())
    c.setEnabled(jcheckBox1.isSelected());
   
En Java 8:

Arrays.stream(jPanel1.getComponents()).forEach(c -> c.setEnabled(jcheckBox1.isSelected()));

Si sólo se quiere procesar los controles que sean cajas de texto:

Arrays.stream(jPanel1.getComponents()).forEach(c -> { if (c instanceof JTextField) c.setEnabled(jcheckBox1.isSelected()); } );

En el caso de .Net, el contenedor es un GroupBox:

foreach (Control c in groupBox1.Controls) 
       c.Enabled = checkBox1.Checked;

Usando Linq será:
groupBox1.Controls.Cast<Control>().ToList().ForEach(c => c.Enabled = checkBox1.Checked);

Si sólo se quiere procesar los controles que sean cajas de texto:
groupBox1.Controls.Cast<Control>().ToList().ForEach(c => { if (c is TextBox) c.Enabled = checkBox1.Checked; });

viernes, 6 de marzo de 2015

Cómo separar el nombre de un archivo y la carpeta donde está almacenado (y otras cosillas de la clase Path)


Basta usar el espacio de nombres System.IO y hacer:

string filePath = "C:\\una Carpeta\\un archivo.txt";

Console.WriteLine(Path.GetFileName(filePath));

Console.WriteLine(Path.GetDirectoryName(filePath));


El resultado es:


De forma inversa, si tengo:

string miarchivo = "un archivo.txt";

string miCarpeta = "C:\\mi Carpeta";

Console.WriteLine(Path.Combine(miCarpeta, miarchivo));

El resultado es:



Path.Combine ya añade el caracter de separación entre miarchivo y miCarpeta.

Por otro lado, si se hace:

Console.WriteLine(Path.DirectorySeparatorChar);

Console.WriteLine(Path.PathSeparator);

El resultado será:


Path.DirectorySeparatorChar devuelve el separador de rutas a archivos y carpetas, Path.PathSeparator devuelve el separador de las rutas de las variables de entorno.

viernes, 6 de febrero de 2015

Comparación entre C# Linq y Java 8 streams

El siguiente código en C# declara un array de strings, filtra aquellos que tengan la cadens "am" y le añade tres puntos al final:


using System;
using System.Linq;

class Program
{
     static void Main()
    {
         string[] names = {"Sam","Pamela", "Dave", "Pascal", "Erik"};
         string[] filteredNames = names.Where(c => c.Contains("am")).Select(c => c + "...").ToArray();
         for (int i = 0; i < filteredNames.Length; i++)
               Console.WriteLine(filteredNames[i]);       
   }
}

El siguiente código en Java 8 hace exactamente lo mismo:

import static java.util.Arrays.stream;

public class HelloWorld
{
     public static void main(String []args)
     {
          String[] names = {"Sam","Pamela", "Dave", "Pascal", "Erik"};
          String[] filteredNames = stream(names).filter(c -> c.contains("am")).map(c-> c + "...").toArray(String[]::new);
          for (int i = 0; i < filteredNames.length; i++)
                  System.out.println(filteredNames[i]);
     }
}


El código en C# corre sobre Mono v3.10 y a partir del .Net Framework 3.5. El código en Java corre a partir del JDK 1.8.

En comparación con Linq, los streams en Java son un poquitillo más complicados de usar, especialmente por la cantidad de casteos que deben hacerse. La ventaja de Linq es que sus métodos como "Select" y "Where" recuerdan a los de SQL. La ventana de los streams de Java es que sus métodos como "map" y "filter" recuerdan a los de Python.

miércoles, 7 de enero de 2015

Código para borrar todos los archivos de una carpeta en Python

El siguiente script recibe como parámetro la carpeta a la que se le quieren eliminar los archivos:

import sys
import os
from os import listdir
from os.path import isfile, join

def delete_Files(folder):
      files_dump = [join(folder, c) for c in listdir(folder)]
      files_dump = filter(lambda c: isfile(c), files_dump)
      [os.remove(c) for c in files_dump]

if __name__ == "__main__":
# sys.argv[0] contiene el nombre del script
# sys.argv[1] contiene el primer parámetro: 
# la carpeta que se desea vaciar
      delete_Files(sys.argv[1])
      print 'Files Deleted!!'


Lo he probado con Python 2.7.8 desde Python Tools for Visual Studio 2013. Se debe tener cuidado porque los archivos son eliminados de forma definitiva, no van a la papelera de reciclaje.

La funcion __name__ puede modificarse para que elimine los archivos de todas las carpetas que se le pasen como argumentos, y sólo en caso de que éstas existan:

if __name__ == "__main__":
      [delete_Files(c) for c in sys.argv[1:] if os.path.exists(c)]
      print 'Files Deleted!!'


Para ingresar los argumentos del script en Visual Studio, se debe ir a Proyecto->Propiedades:



miércoles, 10 de diciembre de 2014

Cómo instalar el servicio de Apache Tomcat 8.0.15

Tengo el JDK 1.8 y el JRE 1.8 instalados en mi Windows 7 64 bits SP1, cuya instalación me creó la siguiente variable de entorno:


Dado que no me creó las variables JAVA_HOME y JRE_HOME, es recomendable añadirlas manualmente.
JAVA_HOME apunta a la carpeta donde está instalado el JDK. JRE_HOME apunta a la instalación del JRE.



Un día decidí trastear, literalmente, una instalación de Tomcat 8.0.15 en mi pc.

Luego de la última instalación, el instalador ya no fue capaz de crear el servicio del Tomcat
Esto lo supe al ejecutar el programa Tomcat8w.exe, pues arrojaba un mensaje de error avisando que no existía el servicio, y éste tampoco aparecía en la lista de servicios en services.msc.

Para instalar el servicio de Tomcat, primero hay que reiniciar el sistema (esto es necesario luego de crear las variables de entorno JAVA_HOME y JRE_HOME).
Después, en una ventana de consola ejecutada como administrador, se debe ir a la carpeta donde está el archivo service.bat: el cual está en la carpeta "bin", dentro de la ruta de instalación del servidor Tomcat (en mi caso dentro de C:\Program Files\Apache Software Foundation\Apache Tomcat 8.0.15\bin) y ejecutar el comando "services.bat install"


Ya con esto, se ha instalado el servicio de Tomcat y es posible entrar a las opciones de configuración ejecutando tomcat8w.exe:


jueves, 27 de noviembre de 2014

Encontrando errores en los archivos xlsx (Ms Excel 2007 - 2010) con Open XML SDK Validation

Entrada original en el blog de Brian Jones (autor Zeyad Rajabi).

Lo único que hice fue acomodar y corregir un poco el código para crear un método que llame al Open XML SDK Validation. Este método escribirá en la ventana de Resultados los errores del archivo xlsx cuya ruta está en la variable "path", y puede ponerse dentro de cualquier clase:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Validation;

static void validarExcel(string path)
{
   OpenXmlValidator validator = new OpenXmlValidator();
   using (SpreadsheetDocument excelFile = SpreadsheetDocument.Open(path, true))
  {
      try
      {
            int count = 0;
            foreach (ValidationErrorInfo error in validator.Validate(excelFile))
            {
                     count++;
                     Trace.WriteLine("Error " + count);
                     Trace.WriteLine("Description: " + error.Description);
                     Trace.WriteLine("Path: " + error.Path.XPath);
                     Trace.WriteLine("Part: " + error.Part.Uri);
                     Trace.WriteLine("-------------------------------------");
             }
      }
      catch (Exception ex)
      {
               Trace.WriteLine(ex.Message);
      }
        excelFile.Close();
    }
}

Por ejemplo, un error que hallé en un archivo xlsx generado desde C# fue que, al ponerles nombres a cada hoja de cada archivo de excel, éstos no pueden tener más de 32 caracteres. Al abrir el archivo xlsx en MS Excel 2010 me tiraba este error (no ocurre en OpenOffice):


 "Registros Reparados: Propiedades de la hoja de /xl/workbook.xml"

Este error se repara en la línea donde se declara el objeto Sheet y se corrige truncando la cadena con el nombre de la hoja a menos de 32 caracteres:

String myName = "nombremuymuymuymuymuymuymuymuymuylargo";

Sheet sheet = new Sheet() { Id = spreadsheet.WorkbookPart.GetIdOfPart(newWorksheetPart), SheetId = worksheetNumber, Name = new string(myName.Take(31).ToArray()) };


Más información en este enlace.

Mike Gledhill tiene una excelente sección acerca de cómo escribir archivos xlsx con Open XML.

martes, 14 de octubre de 2014

Test Fizz Buzz en Python recursivo


Ejecutado y compilado con este compilador online.

def FZ(i):
  if i==0:
    return 0
  else:
    if i%3 == 0 or i%5 == 0:
      if i%3 == 0 and i%5 == 0:
        print "Fizz Buzz"
      else:
        if i%3 == 0:
          print "Fizz"
        if i%5 == 0:
          print "Buzz"
    else:
      print i
  
    return FZ(i-1) 
 
FZ(100)

miércoles, 1 de octubre de 2014

Modificar los datos de un DataTable con Linq en C#

Este post existe gracias a la ayuda de StackOverflow :D

Tengo un DataTable, el cual tiene una columna llamada "Campo1" con datos tipo texto. Quiero que todos los datos que coincidan con un valor sean cambiados por la cadena "Datos por Defecto".
En lugar de usar un bucle, se puede hacer con Linq:

DataTable d = MetodoQueDevuelveUnDataTable();
d.AsEnumerable().ToList<DataRow>().ForEach
   ( r =>
             {
                     if(String.Compare(r["Campo1"].ToString(), "valor que quiero cambiar") == 0)
                          r["Campo1"] = "Datos Por Defecto";
             }
   );

Lo que hace el ForEach es recorrer todas las filas y buscar aquellas donde se cumple la condición y realizar las acciones que deseemos:

DataTable d = MetodoQueDevuelveUnDataTable();
d.AsEnumerable().ToList<DataRow>().ForEach
  ( r =>
             {
                      if(String.Compare(r["Campo1"].ToString(), "valor que quiero cambiar") == 0)
                      {
                           r["Campo1"] = "Datos Por Defecto";
                           r["Campo2"] = Otro Valor;
                       }
             }
  );

Si se desea modificar un valor de uno o más campos determinados en todas las filas, sólo se quita la condición:
 
DataTable d = MetodoQueDevuelveUnDataTable();
d.AsEnumerable().ToList<DataRow>().ForEach
  ( r =>
             {
                 r["Campo1"] = "Datos Por Defecto";
                 r["Campo2"] = Otro Valor;
             }
  );