Detalles de Grupo Privado

administrators

 

Lista de Miembros

  • Codility - Rubidium 2018

    At Deutsche Bank, we’re designing and building the digital bank of the future and you could help shape that. We’re looking for innovative thinkers and curious minds to transform our business through advanced applications, challenging programming projects and cutting-edge tech like AI and blockchain.

    Contest Link: https://app.codility.com/programmers/challenges/rubidium2018/

    publicado en Contests / Challenges
  • React - Cross Platform

    Una práctica que se vuelve común en nuestros días es que las aplicaciones puedan ser compatible con múltiples plataformas, es entonces donde teníamos dificultades para hacer funcionar nuestras aplicaciones diseñadas para la web (ReactDom) en dispositivos móviles por ejemplo (ReactNative).

    Te presento un conjunto de pensamientos simples a la hora de desarrollar y de esta manera puedas reutilizar el código que tienes.

    styled-components/primitives

    Una muy buena práctica que comparten los devs de AirBnb es de no utilizar el abanico de componentes en react-native, en otras palabras intenta hacer todo con los siguientes componentes.

    • Animated: Declarative animations.
    • Image: A base component for Image rendering.
    • StyleSheet: Styling the primitives.
    • Text: A base component for Text rendering.
    • Touchable: A base component for interaction.
    • View: A base component for Layout.

    Segun los desarrolladores que ya utilizan estas primitivas en sus proyectos, un 99% de los componentes necesarios para una aplicación funcional pueden ser totalmente completados con estos.

    direct DOM manipulation

    Siempre que hagas aplicaciones multiplataforma debes tener en cuenta no utilizar o manipular el DOM directamente, facil decir pero a veces complicado implementar.

    En casos extremos donde estás obligado a utilizar el DOM puede que ayas considerado utilizar !!window condición que dará true en web y cuando utilices react-native dara false. En muchos casos puede ser la solución pero si tienes acceso a la configuración de tu proyecto intenta configurar una variable de entorno !!process.env.REACT_DOM de esta forma toma la responsabilidad de tu código y no de la ausencia de la variable window.

    Por último les dejo este video muy util y con buenos consejos y prácticas.

    Video de Leland Richardson (AirBnb)
    React as a Platform: A path towards a truly cross-platform UI - Leland Richardson

    APRENDAMOS DE LOS ERRORES DE OTROS !

    publicado en Software Development
  • React - Estructura de Archivos

    A la hora de estructurar folders y archivos en tu proyecto seguro te haz preguntado que tan amigable es el nombre que escogiste y algunas veces te preguntaras si alguien que está entrando a tu proyecto podrá entender la estructura y encontrar las diferentes secciones de la aplicación.

    https://reactjs.org/docs/faq-structure.html nos algunas pautas de como debemos organizarnos y al mismo tiempo si utilizamos create-react-app nos dara una estructura inicial que es muy común en los proyectos en React dando a todos los desarrolladores una fácil detección de ciertas areas de codigo.

    A la hora de nombrar nuestras carpetas debemos considerar esta regla o al menos intentar nombrar nuestros archivos con una clara idea de lo que contienen eslint-plugin-filenames.

    Ahora hablemos de LIFT una serie de buenas practicas a la hora de elegir nombres de archivos, carpetas y la estructura general de la applicacion.

    • L  —  locating code is easy
    • I  —  identify code at a glance
    • F  —  flat structure as long as we can
    • T  —  try to stay DRY

    LIFT siempre debe estar en nuestro pensamiento a la hora de crear nuevos archivos y folders. Estas de acuerdo ?

    publicado en Software Development
  • Travelling Salesman Challenge 2.0

    Win a trip around the world based on an algorithm you write!

    Type: NP-hard problem

    CONTEST PAGE: https://kiwi2018.sphere-contest.com/

    publicado en Contests / Challenges
  • Listas en C++ (basico)

    Las listas son una de las estructuras básicas para resolver problemas implementando algoritmos.

    A continuación un ejemplo del uso basico de una lista.

    #include <iostream>
    #include <list>
    
    int main () {
      int arrayInts[] = { 75, 23, 65, 42, 13 };
    
      // crea una lista a partir del array
      std::list<int> milista (arrayInts, arrayInts + 5);
    
      milista.push_back(10); // aumenta el numero 10 a la milista.
    
      std::cout << "milista contiene:";
    
      // crea un iterador para recorrer milista.
      std::list<int>::iterator it;
      // milista.begin() retorna un iterador apuntando al inicio de milista.
      // milista.end() retorna un iterador apuntando al final de milista.
      for (it = milista.begin(); it != milista.end(); ++it)
        std::cout << ' ' << *it;
      std::cout << '\n';
    }
    

    El anterior código imprime como resultado en consola:
    milista contiene: 75 23 65 42 13 10

    Por el momento no vimos ninguna diferencia entre una lista y un vector o array, pero las listas tienen una gran ventaja a la hora de insertar nuevos números en medio de la lista y también a hora de eliminar números en la lista.

    La complejidad para insertar un número es de $O(1)$ pero es necesario tener un iterador en el lugar donde necesitas insertar el número entonces si necesitas llegar desde el inicio de la lista buscando un numero en especial necesitarás $O(p)$ pasos utilizando un it++ para ir avanzando.

    Al igual que insertar para eliminar un valor es necesario un iterador ya que una lista no tiene índices al igual que un array pero si ya estas apuntando al nodo que necesitas eliminar entonces la complejidad será $O(1)$

    #include <iostream>
    #include <list>
    #include <vector>
    
    int main () {
      std::list<int> mylist;
      std::list<int>::iterator it;
    
      // aca añadimos los valores iniciales
      for (int i=1; i<=5; ++i) mylist.push_back(i); // 1 2 3 4 5
    
      // begin() retorna un puntero al primer valor    ^
      it = mylist.begin();
      ++it;       // "it" apunta al numero 2             ^
    
      mylist.insert (it, 10);                       // 1 10 2 3 4 5
    
      // "it" aun apunta al numero 2                        ^
      mylist.insert (it, 2, 20);                    // 1 10 20 20 2 3 4 5
    
      --it;       // "it" ahora apunta al segundo 20           ^
    
      std::vector<int> myvector (2, 30);
      mylist.insert (it,myvector.begin(), myvector.end());
                                                    // 1 10 20 30 30 20 2 3 4 5
                                                    //               ^
      std::cout << "mylist contiene:";
      for (it=mylist.begin(); it!=mylist.end(); ++it)
        std::cout << ' ' << *it;
      std::cout << '\n';
    
      return 0;
    }
    

    El anterior código imprime lo siguiente en la consola:
    mylist contiene: 1 10 20 30 30 20 2 3 4 5

    Cuando utilizo C++ y no recuerdo o necesito buscar algunas estructuras o funciones utilizó cplusplus.com y en este caso los ejemplos fueron una traducción de esta página.

    referencias:
    cplusplus list

    publicado en Data Structures
  • Grafos - Algoritmo básico de búsqueda DFS (Parte 3.2)

    Existen dos algoritmos básicos para recorrer un grafo o buscar un nodo en particular, la búsqueda por anchura o BFS y la búsqueda por profundidad o DFS. En este artículo explicaremos la búsqueda por profundidad (DFS).

    El algoritmo de la búsqueda por profundidad se puede hacer modificando el anterior (Parte 3.1 BFS) en la parte que usa una cola y usar una pila. Otra forma de implementarla es usando recursividad, a continuación se muestran ambos enfoques así como la rutina para hacer la búsqueda en grafos que no están completamente conectados.

    A continuación se presenta el listado con la implementación de la búsqueda por profundidad o DFS. También se ha añadido en la versión recursiva un contador que marca el orden en el que fueron visitados los nodos del grafo, dicho orden es muy útil al implementar otros algoritmos de grafos.

    Implementación DFS (usando una pila)

    int visitado[1000];
    vector<list<int> > grafo(1000);
    
    void DFS(int v) { //v es el nodo de inicio del recorrido
      list<int> pila; //pila de nodos adyacentes
      list<int>::iterator nodo_actual, aux, fin;
      visitado[v] = 1; //marcar como visitado el nodo de inicio
      pila.push_back(v);
      while (!pila.empty()) { //mientras no se vacie la pila de adyacentes
        nodo_actual = pila.back();
        //aqui podriamos marcar el orden en que se visitaron
        pila.pop_back();
        aux = grafo[nodo_actual].begin(); // posicionar iteradores para
                                          // lista adyacente
        fin = grafo[nodo_actual].end();
        while (aux != fin) { //recorrer todos los adyacente al nodo actual
          if (!visitado[*aux]) { //añadir a la pila solo los no visitados
            visitado[*aux] = 1;
            pila.push_back(*aux);
            //aqui podemos añadir código para hacer algo mientras
            //realizamos el recorrido
          }
          aux++; //avanzar al siguiente adyacente del nodo actual
        }
      }
    }
    

    Implementacion DFS (recursiva)

    int visitado[1000];
    vector<list<int> > grafo(1000);
    
    void DFS(int v) {
      list<int>::iterator aux, fin; //iteradores para lista de ady
      visitado[v] = 1; //marcar como visitado
      //aqui se podria marcar el orden en que fueron visitados
      aux = grafo[v].begin(); //posicionar los iteradores para lista de ady
      fin = grafo[v].end();
      while (aux != fin) {
        if (!visitado[*aux])
          DFS(*aux); //no se necesita marcar porque *aux se convierte en v
        aux++; //avanzar al siguiente adyacente de v
      }
    }
    
    //esta es la version para grafos que no estan completamente conectados
    void DFS2() {
      int i;
      for (int i = 0; i < nvert; i++) //buscar un nuevo nodo de
        if  (!visitado[i])            //inicio que no ha sido visitado
          DFS(i);
    }
    

    En esta implementación podrán ver que primero se visitan los nodos o vértices que fueron visitados al final, en este caso los números que se encuentran en la pila tienen como primer número al último que fue ingresado.

    0_1537932896697_thomas miller (2).png

    Por ejemplo para el grafo de la figura si comenzamos la búsqueda por el nodo cero (0).

    0. Inicio DFS(0)
        nodoActual = -1, pila = [0]
    1. Sacamos el primer nodo de la pila
        nodoActual = 0, pila = []
    2. 0 visitara a DFS(1) y DFS(3)
        nodoActual = 0, pila = [1, 3]
    3. Sacamos el primer nodo de la pila
        nodoActual = 3, pila = [1]
    4. 3 visitara a DFS(2) y DFS(4)
        nodoActual = 3, pila = [1, 2, 4]
    5. Sacamos el primer nodo de la pila
        nodoActual = 4, pila = [1, 2]
    6. 4 no visita a ningun nodo
        nodoActual = 4, pila = [1, 2]
    7. Sacamos el primer nodo de la pila
        nodoActual = 2, pila = [1]
    8. 2 visitara a DFS(4) pero 4 ya fue visitado
        nodoActual = 2, pila = [1]
    9. Sacamos el primer nodo de la pila
        nodoActual = 1, pila = []
    10. El algoritmo termina por la pila esta vacía
    

    En el caso de la implementación recursiva deberán hacerla correr con un ejemplo de grafo para poder analizar la pila, cuando las funciones se llaman recursivamente verán que no se llama a una sin que termine la última en ser llamada y a su vez esperará hasta que todas las funciones llamadas por la otra función sean terminadas.

    #include <iostream>
    #include <vector>
    #include <list>
    using namespace std;
    
    int visitado[1000];
    vector<list<int> > grafo(1000);
    
    void DFS(int v) {
      list<int>::iterator aux, fin; //iteradores para lista de ady
      visitado[v] = 1; //marcar como visitado
      //aqui se podria marcar el orden en que fueron visitados
      cout << v << " fue visitado" << endl;
      aux = grafo[v].begin(); //posicionar los iteradores para lista de ady
      fin = grafo[v].end();
      while (aux != fin) { // este ciclo extra esta para imprimir los siguientes nodos
        cout << '\t' << (*aux) << " sera visitado por " << v << endl;
        aux++; //avanzar al siguiente adyacente de v
      }
      aux = grafo[v].begin(); //posicionar los iteradores para lista de ady
      fin = grafo[v].end();
      while (aux != fin) {
        if (!visitado[*aux])
          DFS(*aux); //no se necesita marcar porque *aux se convierte en v
        aux++; //avanzar al siguiente adyacente de v
      }
    }
    
    int main() {
      // conectamos el grafo
      grafo[0].push_back(1);
      grafo[0].push_back(3);
      grafo[1].push_back(2);
      grafo[1].push_back(3);
      grafo[2].push_back(4);
      grafo[3].push_back(2);
      grafo[3].push_back(4);
      // llamamos a la funcion DFS
      DFS(0);
    }
    

    Para practicar con este tipo de busqueda puedes utlizar uno de los siguientes enlaces:

    publicado en Grafos
  • Grafos - Algoritmo basico de busqueda BFS (Parte 3.1)

    Existen dos algoritmos básicos para recorrer un grafo o buscar un nodo en particular, la búsqueda por anchura o BFS y la búsqueda por profundidad o DFS. En este articulo explicaremos la búsqueda por anchura (BFS).

    A continuación se muestra el algoritmo de la búsqueda por anchura en un grafo representado por medio de listas de adyacencias. En dicho algoritmo se usa una cola para almacenar los nodos adyacentes al actual y guardarlos para continuar con la búsqueda. La siguiente implementación del recorrido por anchura para un grafo completamente conectado (existe al menos un camino entre cualquier par de vértices en el grafo) y para un grafo que no lo esta.

    int visitado[1000];
    vector<list<int> > grafo(1000);
    
    // algoritmo para grafo completamente conectado
    void BFS(int v) { // v es el nodo de inicio del recorrido
      list<int> cola; // cola de adyacentes
      list<int>::iterator nodo_actual, aux, fin;
      visitado[v] = 1; // marcamos como visitado el nodo de inicio
      cola.push_back(v); // metemos inicio a la cola
      while (!cola.empty()) {
        nodo_actual = cola.front(); // sacar nodo de la cola
        cola.pop_front();
        aux = grafo[nodo_actual].begin(); //posicionar iteradores para
                                          //lista de ady
        fin = grafo[nodo_actual].end();
        while (aux != fin) {      // recorrer todos los nodos ady a nodo actual
          if (!visitado[*aux]) {  // añadir a la cola solo los no visitados
            visitado[*aux] = 1;   // marcarlos como visitados
            cola.push_back(*aux); // añadirlos a la cola
            // aqui podriamos añadir codigo para hacer algo mientras
            // recorremos el grafo
          }
          aux++; // avanzar al siguiente adyacente del nodo actual
        }	   
      }
    }
    
    // algoritmo para grafo que no esta completamente conectado
    void BFS2() {
      for (int i = 0; i < nvert; i++)
        if (!visitado[i])
          BFS(i);
    }
    

    En esta implementación podrán ver que primero se visitan los nodos o vértices que fueron visitados primero.

    0_1537932896697_thomas miller (2).png

    Por ejemplo para el grafo de la figura si comenzamos la búsqueda por el nodo cero (0).

    0. Inicio BFS(0)
        nodoActual = -1, cola = [0]
    1. Sacamos el primer nodo de la cola
        nodoActual = 0, cola = []
    2. 0 visitara a BFS(1) y BFS(3)
        nodoActual = 0, cola = [1, 3]
    3. Sacamos el primer nodo de la cola
        nodoActual = 1, cola = [3]
    4. 1 visitara a BFS(2) y BFS(3) pero 3 ya fue visitado
        nodoActual = 1, cola = [3, 2]
    5. Sacamos el primer nodo de la cola
        nodoActual = 3, cola = [2]
    6. 3 visitara a BFS(2) y BFS(4) pero 2 ya fue visitado
        nodoActual = 3, cola = [2, 4]
    7. Sacamos el primer nodo de la cola
        nodoActual = 2, cola = [4]
    8. 2 visitara a BFS(4) pero 4 ya fue visitado
        nodoActual = 2, cola = [4]
    9. Sacamos el primer nodo de la cola
        nodoActual = 4, cola = []
    10. El algoritmo termina por la cola esta vacía
    

    Para practicar con este tipo de busqueda puedes utlizar uno de los siguientes enlaces:

    publicado en Grafos
  • Hacktoberfest 2018

    Support opensource and earn a limited edition T-shirt


    Who

    Hacktoberfest is open to everyone in our global community!

    How

    Pull requests can be made in any GitHub-hosted repositories/projects.

    When

    You can sign up anytime between October 1 and October 31.

    Hacktoberfest 2018

    publicado en Contests / Challenges
  • Software Developer Challenges

    Todos sabemos que en el desarrollo de Software no hay expertos con conocimientos completos, todo experto en su área dia a dia tiene que actualizarse estudiar nuevas tendencias, analizar nuevo código de otros expertos y sobre todo leer la nueva documentación del dia a dia.

    Lo que hace difícil esto es que después de leer la documentación, ver videos/tutoriales a veces no tienes con quien trabajar o ver y analizar código.

    En Algoritmos o Competencias de Programación aprendí que una vez que terminas de leer todo un area de teoría el siguiente paso viene a ser competir y resolver problemas intentando topar con ejercicios del area que buscas volverte experto.

    Es por eso que te presento una pagina conocida por muchos y con competencias en distintas tecnologías y lenguajes en el área de software donde encontrarás expertos del area compitiendo contra ti y te dara paso ha aprender muchas cosas nuevas.

    Lista de algunas sugerencias:

    TopCoder - NodeJS
    TopCoder - Python
    TopCoder - Java
    TopCoder - Angular
    TopCoder - ReactJS
    TopCoder - Android

    Si tu lenguaje o tecnología no esta listado puedes intentar usar la pagina de Challenges para buscar y filtrar lo que andas buscando:

    TopCoder - Challenges

    publicado en Software Development
  • Grafos - Metodos de representación en computadora (Parte 2)

    Tal y como adelantamos en la Parte 1 ahora aprenderemos cómo representar los Grafos en código.

    Matriz de Adyacencias

    Con este método se tiene una matriz de tamaño $[n*n]$ donde n es el número de vértices o nodos en el Grafo.

    Una forma simple de ver la información guardada en dicha matriz es que los renglones de las mismas representan el origen y las columnas el destino de cada arista o arco en el Grafo. Si el grafo es no ponderado se acostumbra poner un cero en la [fila $i$, columna $j$] de la matriz cuando no existe dicho arco y un uno cuando dicho arco existe en el Grafo. En el caso de grafos ponderados, se acostumbra poner una bandera (normalmente el valor de infinito) en las posiciones donde no existe un arco y el peso correspondiente en las posiciones donde sí existe.

    Figura 1. Grafo No Ponderado y su Matriz de Adyacencias

    Figura 1. Grafo No Ponderado y su Matriz de Adyacencias

    Debe notarse que para un grafo no dirigido la Matriz de Adyacencia es simétrica y que la diagonal principal contiene ceros. Esto puede llegar a aprovecharse para ahorrar tiempo en algunos algoritmos. La representación por medio de matriz se prefiere para algoritmos donde el número de arcos es grande en proporción al número de vértices. Si sucediera lo contrario se prefiere la representación por medio de Listas de Adyacencia.

    0_1537931783908_thomas miller (1).png

    Figura 2. Digrafo Ponderado y su Matriz de Adyacencias

    Codigo en C++ de la Figura 1

    #include <iostream>
    using namespace std;
    
    int main() {
      int n = 5;
      int G[n][n];
      memset(G, 0, sizeof(G));
      G[0][1] = G[1][0] = 1;
      G[1][2] = G[2][1] = 1;
      G[3][2] = G[2][3] = 1;
      for (int i = 0; i < n ; i++) {
        for (int j = i + 1; j < n ; j++) {
          if (G[i][j]) {
            cout << i << " esta conectado con " << j << endl;
          }
        }
      }
    }
    
    

    Listas de Adyacencias

    Para representar un Grafo mediante Listas de Adyacencias como su nombre lo indica se utiliza la estructura de datos de Listas enlazadas, para lo cual por cada vértice o nodo se crea una Lista donde se contiene a todos los vértices a los cuales podemos visitar a partir de este.

    0_1537932896697_thomas miller (2).png

    Figura 3. Digrafo y su Listas de Adyacencias

    Codigo en C++ de la Figura 3

    #include <iostream>
    #include <vector>
    #include <list>
    using namespace std;
    
    const int MAX_VERT = 5;
    vector<list<int> > grafo(MAX_VERT);
    bool visitado[MAX_VERT];
    
    void inserta_arista(int i, int j){
      grafo[i].push_back(j);
    }
    
    void limpia_grafo() {
      for (int i = 0; i < MAX_VERT; i++) {
        visitado[i] = 0;
        grafo[i].clear();
      }
    }
    
    int main() {
      limpia_grafo();
      inserta_arista(0, 1);
      inserta_arista(0, 3);
      inserta_arista(1, 2);
      inserta_arista(1, 3);
      inserta_arista(2, 4);
      inserta_arista(3, 2);
      inserta_arista(3, 4);
    
      list<int>::iterator it;
      for (it = grafo[3].begin(); it != grafo[3].end() ;it++) {
        cout << "3 puede visitar a " << (*it) << endl;
      }
    }
    

    Si buscamos representar un Digrafo Ponderados utilizando Listas de Adyacencia sera necesario utilizar una lista de pares del tipo $G[v_i] = [(v_0, w_0), (v_1, w_1), ..., (v_j, w_j) ]$

    En C++ esta lista se representaria con el siguiente código:

    vector<list<pair<int, int> > > grafo(MAX_VERT);
    
    publicado en Grafos