JavaScript: Enlever les doublons d’un tableau

La fonction suivante permet de se débarrasser des doublons présents dans
un tableaux avec élégance.

//cleanArray removes all duplicated elements
function cleanArray(array) {
  var i, j, len = array.length, out = [], obj = {};
  for (i = 0; i < len; i++) {
    obj[array[i]] = 0;
  }
  for (j in obj) {
    out.push(j);
  }
  return out;
}

On va créer un tableau associatif avec chaque valeur présente dans le
tableau passé en paramètre. Ainsi, lorsqu’un doublon est rencontré,
l’ajout d’un champ avec le même index n’a pas d’effet. On parcourt
ensuite ce tableau et l’on stocke les indexes dans le tableau out qui
sera retourné.

Exemple:

var nbr = [42, 101010, 7, 42, 7, 42, 101010];
var newNbr = cleanArray(nbr);
console.log(newNbr);

Qui donnera:

["42", "101010", "7"]

 

API Google Maps

J’ai eu l’occasion la semaine dernière, de jouer avec l’API Google Maps. Récupération de données en json auprès d’un serveur en lui demandant de filtrer les résultats sur la valeur d’un champ. Je présente ici, une version simplifiée, j’ai placé des données en dur dans mon fichier .js, quelques gares: Nom, Région, Latitude, Longitude, et je m’arrange pour afficher leur position avec l’API de Google.

On prépare d’abord la page Html qui va recevoir le tout. On ajoute le JS de l’API:

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=VOTRE_CLE&sensor=false">
</script>

En remplaçant VOTRE_CLE par la cle d’API générée par Google.

On place une balise <div> pour accueillir la map une fois celle-ci générée.

Initialisation de la Google Maps

var mapOptions = {
  center: new google.maps.LatLng(47.2, 2),
  zoom: 5,
  mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"),
  mapOptions);

Pour créer un marqueur:

var latlng = new google.maps.LatLng(latitude, longitude);
var marker = new google.maps.Marker({
  position: latlng,
  title: "Titre du marqueur"
});
marker.setMap(map);

Concernant la gestion des marqueurs, depuis la dernière version de Google Maps, il est nécessaire de les gérer soit même. Il faut donc garder une trace des marqueurs pour pouvoir les supprimer par la suite, si besoin. On stockera les marqueurs dans un tableau.

var markersArray = [];

On ajoute les marqueurs au tableau après le placement sur la carte.

markersArray.push(marker);

La fonction pour supprimer tous les marqueurs du tableau de la carte et nettoyer la carte est deleteOverlays().

Pour créer une OpenWindow:

var infowindow = new google.maps.InfoWindow({
  content: contentString
});

//Ajout d'un Listener sur le marqueur pour réagir en cas de clic
google.maps.event.addListener(marker, 'click', function() {
  infowindow.open(map,marker);
});

Obtenir votre clé d’API Google Maps
Aller sur https://code.google.com/apis/console et se connecter avec son compte Google.
Cliquer sur Services dans le menu à gauche.
Activer le service Google Maps API v3.
Cliquer sur API Access dans le menu à gauche.
La clé est visible dans la page API Access, section Simple API Access, celle-ci est indiqué sous le nom de Key for browser apps.

Le code:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <link rel="stylesheet" href="style.css" />
        <title>Gare de France</title> 

        <script src="jquery.js"></script>
    <script src="getdata.js"></script>
    <script type="text/javascript"
        src="http://maps.googleapis.com/maps/api/js?key=VOTRE_CLE&sensor=false">
        </script>
    </head> 

 <body>
    <div id="map_canvas"></div> 

    <div id="gareTab">
        <h1>Liste de Gares Françaises</h1> 

        <table><tr>  <th>Nom de la gare</th> <th>Région</th> <th>Latitude</th>   <th>Longitude</th>  </tr></table>
    </div>
 </body>
</html>

Côté CSS, on aura:

html {
      height: 100%
}
body {
    height: 100%;
    margin: 0;
    padding: 0;
    margin-left: 2em;
    margin-top: 2em;
}
table {
    border-collapse: collapse;
}
td, th {
    border: 1px solid black;
    padding-left: 5px;
    padding-right: 5px;
}
#map_canvas {
     display: inline-block;
     position: absolute;
     margin-top: 6em;
     width: 50%;
     height: 55%;
     left: 45%
 }
#gareTab {
     position: absolute;
     width: 60%;
     margin-top: 6em;
 }

Et enfin, passons au côté JavaScript proprement dit:

//Contient tous les marqueurs présents sur notre carte
var markersArray = [];
//On retient l'InfoWindow ouverte pour pouvoir la fermer au besoin
var openedInfoWindow;
//Nos données
var data = [
            {
                "Nom de la gare": "Amiens",
                "Région": "Picardie",
                "Latitude": "49.88993025",
                "Longitude": "2.30981909"},
            {
                "Nom de la gare": "Lyon-Part-Dieu",
                "Région": "Rhône-Alpes",
                "Latitude": "45.76032897",
                "Longitude": "4.86050906"},
            {
                "Nom de la gare": "Bas-Monistrol",
                "Région": "Auvergne",
                "Latitude": "45.29796638",
                "Longitude": "4.13958253"},
            {
                "Nom de la gare": "Strasbourg",
                "Région": "Alsace",
                "Latitude": "48.58496713",
                "Longitude": "7.734584"}, 

            {   "Nom de la gare": "Quiberon",
                "Région": "Bretagne",
                "Latitude": "47.48552763",
                "Longitude": "-3.11816733"},
            {
                "Nom de la gare": "Carcassonne",
                "Région": "Languedoc-Roussillon",
                "Latitude": "43.21816508",
                "Longitude": "2.35242959"}
            ]; 

//Suppression des marqueurs Google Maps
function deleteOverlays() {
  if (markersArray) {
    for (i in markersArray) {
      markersArray[i].setMap(null);
    }
    markersArray.length = 0;
  }
} 

//Suppression du contenu du tableau de gare
function deleteTab() {
    for(var i = 0; i < $('.ligne').length; ++i) {
        $('.ligne').remove();
    }
} 

//S'exécute lorsque le document est prêt
function readyFn() { 

    //Initialisation de la Google Maps
    var mapOptions = {
        center: new google.maps.LatLng(47, 2),
        zoom: 6,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    }; 

    map = new google.maps.Map(document.getElementById("map_canvas"),
    mapOptions); 

    //Suppression de tout ce qui pourrait préexister
    deleteOverlays();
    deleteTab(); 

    var tab = [];//On construit le contenu du tableau HTML dans tab
    data.forEach(function(element, index, array) {
        //Construction d'une ligne du tableau
        tab.push('<tr><td> ' +
            element["Nom de la gare"] + ' </td><td>' +
            element["Région"] + ' </td><td>  ' +
            element["Latitude"] + '  </td><td>  ' +
            element["Longitude"] + '  </td></tr>'
        ); 

        //Construction du marqueur Google Maps
        var latlng = new google.maps.LatLng(element["Latitude"], element["Longitude"]);
        var marker = new google.maps.Marker({
            position: latlng,
            title: element["Nom de la gare"]
         });
        marker.setMap(map);//Ajout du marqueur à la carte
        markersArray.push(marker); 

        //Ajout d'une InfoWindow pour chaque marqueur
        //Ce qui s'affichera:
        var contentString = '<b>' + element["Nom de la gare"]
            + '</b><br />' + element["Région"]
            + '<br />Latitude: ' + element["Latitude"]
            + '<br />Longitude: ' + element["Longitude"]; 

        //Création des fenêtres d'info (ou InfoWindow)
        var infowindow = new google.maps.InfoWindow({
            content: contentString
        }); 

        //Ajout d'un Listener sur le marqueur pour réagir en cas de clic
        google.maps.event.addListener(marker, 'click', function() {
            if(openedInfoWindow != undefined) {//Au cas où il n'y a pas d'info window à fermer
                openedInfoWindow.close();
            }
            infowindow.open(map,marker);
            openedInfoWindow = infowindow;
        });
    }); 

    //concaténation du tableau en string et ajout dans la balise table
    $('table').append(tab.join(''));
} 

$(document).ready(readyFn);

 

Pour tout savoir sur l’API Google Maps, je vous conseille la doc de Google qui est très claire et détaillée:
https://developers.google.com/maps/documentation/javascript/tutorial

Pour le zip contenant les fichiers ci-dessus, c’est par ici:

GareOnGoogleMaps

Maj 25.03.2013: En fait, il n’est pas nécessaire de générer une clé d’API pour pouvoir utiliser la Google Maps. Il suffit simplement d’utiliser l’url suivante http://maps.googleapis.com/maps/api/js?&sensor=false correspondant à l’adresse utilisée dans cette exemple sans le paramètre key. Ajout du zip comprenant les sources.

Code Camp 8 – 9 Juin 2012

Bonsoir amis de la nuit… Ou bonjour, c’est selon.

Un petit article dédié à notre hackaton à nous étudiants, j’ai nommé le « Code Camp ».
Le principe est simple, une nuit de 20h à 6 ou 7h le lendemain, dédiée à l’avancement de nos projets, qu’ils soient de programmation ou non, scolaires ou pas.

Pour ma part, j’ai étudié pendant une bonne partie de ce début de soirée les interfaces graphiques en java, avec Swing notamment.
Finalement, après quelques heures de recherches et de tâtonnements, j’ai pu maintenant doter notre programme de gestion des feux de circulation d’une ville d’une première ébauche d’interface graphique.
Si notre projet fonctionne correctement du point de vue de la ligne de commande, l’aspect graphique d’un programme est une autre paire de manche, qu’il faut apprivoiser et comprendre.
Reste maintenant à continuer de lier notre modèle avec la vue et les contrôleurs.

Bref, on découvre de nouvelles choses et on rencontre des nouvelles difficultés à surmonter.

Sur ce, je vous souhaite une bonne nuit.

Conky sous GNU/Linux

Bonsoir chers lecteurs, bonsoir Google Bot et autres.

Ce soir, un petit article sur conky, programme permettant d’afficher sur votre bureau divers informations concernant votre système, comme par exemple l’uptime de la machine, le % d’utilisation du CPU, l’utilisation de la RAM, l’occupation de vos disques durs ou encore, le titre de musique joué dans RhytmBox.

L’installation s’effectue via un simple sudo apt-get install conky. Il est parfois nécessaire de s’adapter, conky n’étant pas toujours disponible dans les dépôts de toutes les distributions GNU/Linux et il est parfois nécessaire d’ajouter des dépôts de type « non-free ». C’est le cas pour Debian, puisque conky est passé dans le dépôts « non-free » suite à une mise à jour. Néanmoins, l’installation reste à la portée de tous ;).

La configuration des informations à afficher est réalisée via le fichier .conkyrc situé dans votre home directory. Un Ctrl + H vous permettra de le rendre visible. Pour ceux qui n’ont jamais vu à quoi peut ressembler un conky, voilà le mien, remis en place ce soir et légèrement reconfiguré depuis sa dernière utilisation.

Pour ce qui est du code de configuration associé, le voici:

# set to yes if you want Conky to be forked in the background
background yes

cpu_avg_samples 2
net_avg_samples 2

out_to_console no

# Use Xft?
use_xft yes

# Xft font when Xft is enabled
xftfont Bitstream Vera Sans Mono:size=8

own_window        yes    # On dit à Conky de ne pas se mettre sur le bureau mais dans une fenêtre propre
own_window_type   override  # type de fenêtre "maison" (le type desktop convient si on n'a pas d'ombre)
own_window_hints  undecorated,below,sticky,skip_taskbar,skip_pager # définition du type
own_window_transparent yes
own_window_colour hotpink

# Text alpha when using Xft
xftalpha 0.8

on_bottom yes

# Update interval in seconds
update_interval 1

# Use double buffering (reduces flicker, may not work for everyone)
double_buffer yes

# Minimum size of text area
#minimum_size 280 5
#maximum_width 150

# Draw shades?
draw_shades no

# Draw outlines?
draw_outline no

# Draw borders around text
draw_borders no

# Stippled borders?
stippled_borders 10

# border margins
border_margin 4

# border width
border_width 1

# Default colors and also border colors
default_color white
default_shade_color white
default_outline_color white

# Text alignment, other possible values are commented
#alignment top_left
#minimum_size 10 10
gap_x 13
gap_y 34
alignment top_right
#alignment bottom_left
#alignment bottom_right

# Gap between borders of screen and text

# Add spaces to keep things from moving about?  This only affects certain objects.
use_spacer no

# Subtract file system buffers from used memory?
no_buffers yes

# set to yes if you want all text to be in uppercase
uppercase no

TEXT
$nodename - $sysname $kernel on $machine
$stippled_hr
${color lightgrey}Uptime:$color $uptime ${color lightgrey}- Load:$color $loadavg
${color lightgrey}CPU Usage:${color #5000a0} ${cpu}% ${cpubar}
${color black}${cpugraph 000000 5000a0}
${color lightgrey}RAM:$color $mem/$memmax - $memperc% $membar
${color lightgrey}Swap:$color $swap/$swapmax - $swapperc% ${swapbar}
${color lightgrey}Processes:$color $processes  ${color grey}Running:$color $running_processes

${color lightgrey}Temperatures:
 CPU:$color ${hwmon 0 temp 2}°C${color grey} - MB:$color ${hwmon 0 temp 1}°C

${color lightgrey}Batterie: $color${battery BAT0} ${battery_bar 5,120} ${battery_percent}%
$color$stippled_hr
${color lightgrey}File systems:
 /        $color${fs_used /}/${fs_size /} ${fs_bar 5,120 /}
$color$stippled_hr
${if_gw}${alignc}${gw_iface}: ${addrs eth0} Gateway: ${gw_ip}${endif}
Down ${offset 45}${totaldown eth0} ${offset 8}    Up ${alignr}${totalup eth0}
${downspeedgraph eth0 22,150 5e7b7b d8deeb} ${upspeedgraph eth0 22,150 99c8e8 618094}
${offset 40}${voffset -21}${downspeedf eth0}k/s
${offset 190}${voffset -14}${upspeedf eth0}k/s
$color$stippled_hr
${color}Name              PID     CPU%   MEM%
${color #ddaa00} ${top name 1} ${top pid 1} ${top cpu 1} ${top mem 1}
${color lightgrey} ${top name 2} ${top pid 2} ${top cpu 2} ${top mem 2}
${color lightgrey} ${top name 3} ${top pid 3} ${top cpu 3} ${top mem 3}
${color}Mem usage
${color #ddaa00} ${top_mem name 1} ${top_mem pid 1} ${top_mem cpu 1} ${top_mem mem 1}
${color lightgrey} ${top_mem name 2} ${top_mem pid 2} ${top_mem cpu 2} ${top_mem mem 2}
${color lightgrey} ${top_mem name 3} ${top_mem pid 3} ${top_mem cpu 3} ${top_mem mem 3}

${color #FFFFFF} ${top_mem name 1} ${top_mem pid 1} ${top_mem cpu 1} ${top_mem mem 1}
${color #FFFFFF} ${top_mem name 2} ${top_mem pid 2} ${top_mem cpu 2} ${top_mem mem 2}
${color #FFFFFF} ${top_mem name 3} ${top_mem pid 3} ${top_mem cpu 3} ${top_mem mem 3}
${color #FFFFFF} ${top_mem name 4} ${top_mem pid 4} ${top_mem cpu 4} ${top_mem mem 4}

${if_running rhythmbox}
${color lightgrey}${alignc}RhythmBox Now Playing :
${alignc}${exec rhythmbox-client --print-playing-format "%ta - %at"}
${alignc}${exec rhythmbox-client --print-playing-format "%tn - %tt"}
${endif}

La fenêtre ci-dessus ne pas très pratique pour la lecture, je mettrai certainement un lien vers le fichier. Pour lancer conky, taper conky dans un terminal. Dans mon cas, le résultat s’affiche en haut à droite de l’écran. A priori, le démarrage se fait automatiquement à l’ouverture de la session dans la dernière version grâce à l’appel du script .conkyboot.sh, situé dans le dossier .conky.

Algorithme de recherche des nombres premiers

Aujourd’hui, nous nous intéressons aux nombres premiers et à la façon de les trouver. Pour cela, voilà un algorithme assez simple qui permet de trouver un nombre n de nombre premier. Dans sa première version, l’algorithme recommençait à calculer à partir de 5 (si ma mémoire est bonne ;) ) à chaque exécution. Dans sa version actuelle, nous pouvons maintenant reprendre les calculs à partir du dernier nombre premier trouvé. Quelques améliorations pourront néanmoins être apporter comme la possibilité d’interrompre le programme alors qu’il teste des nombres et de le relancer sans avoir à repartir du dernier nombre premier, la gestion des grands nombres pourrait être à revoir. Nous pouvons également envisager la division du fichier contenant les nombres premiers en plusieurs autres fichiers tous les x nombres.

L’algorithme est présenté en code C et repose sur ce que mon professeur de sécurité désignait il y a quelques jours comme la « méthode naïve »; puisqu’il existe d’autres méthodes, permettant de s’assurer qu’un nombre n’est pas premier entre autres (mais pas d’équivalence ici, si le nombre n’est pas premier, le théorème ne permet pas de monter qu’il l’est) et dont je parlerais certainement dans un autre article.

Au jour d’aujourd’hui, notre fichier fait 969 376 620 octets et est trop grand pour être ouvert par certains éditeur de texte :D.  Pour déterminer si un nombre est premier, l’algorithme va regarder le résultat de la division du nombre testé par les nombres premiers déjà présent dans le fichier. Si le reste vaut 0, le nombre testé est divisible par un autre nombre que 1 ou lui-même, il n’est donc pas premier. On peut arrêter ce test, lorsque le nombre premier utilisé dans la division euclidienne est supérieur à la racine carré du nombre testé et ainsi gagner du temps. De même, l’incrémentation des nombres testés de 2 en 2 à partir d’un entier impair permet de ne jamais tester les nombres pairs puisque nous les savons tous divisibles par 2. Le lien vers un dossier contenant le code et les fichiers qu’il utilise: Algorithme Nombres Premiers. Place maintenant au programme:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int premier(int test);

int main(void)
{
    /*VARIABLE:
      recherche: le nombre de nombre premier à rechercher
      dernier: le dernier nombre testé
        lors de l'appel précédent au programme,
        contenu dans dernier.txt*/

    int recherche, dernier;
    FILE *fichier_dernier_nbr;
    FILE  *fichier;
    recherche=100;
    dernier=0;

    /*Initialisation du dernier nombre testé
      dernier est obligatoirement impair*/
    fichier=NULL;
    fichier_dernier_nbr = NULL;
    fichier_dernier_nbr = fopen("dernier.txt", "r+");

    if (fichier_dernier_nbr != NULL)
    {
        fscanf(fichier_dernier_nbr, "%d", &dernier);
        fclose(fichier_dernier_nbr);
    }

    /*On recherche autant de nombre premier
       que le contenu de recherche*/
    while(recherche>0)
    {
        if(premier(dernier))
        {
            /*Le nombre testé est premier*/
            /*printf("%d:Premier\n", dernier);*/
            /*On enregistre le nombre à la fin du fichier*/
            fichier = fopen("test.txt", "r+");
            fseek(fichier, 0, SEEK_END);
            fprintf(fichier, "%d\n", dernier);
            fclose(fichier);
            /*On décrémente le nombre de nombre premier
              encore à trouver*/
            recherche--;
        }
        dernier=dernier+2;
    }
    /*On enregistre le dernier à la fin du fichier*/
    fichier = fopen("dernier.txt", "w+");
    fseek(fichier, 0, SEEK_SET);
    fprintf(fichier, "%d", dernier);
    fclose(fichier);

    printf("Operation effectuee avec succes.\n");

    return EXIT_SUCCESS;
}

/*Renvoi 1 si le nombre est un nombre premier*/
int premier(int test)
{
    int nb_premier;
    int borne=0;

    FILE* fichier = NULL;
    fichier = fopen("test.txt", "r+");

    if (fichier != NULL)
    {

        while(feof(fichier)==0 && borne==0)
        {    
            fscanf(fichier, "%d", &nb_premier);
            /*printf("%d\n", nb_premier);*/
            /*Nombre divisible par un nombre premier,
              premier(test)=0*/
            if(test%nb_premier==0)
            {
                fclose(fichier);
                return 0;
                }
            /*Si la racine carré du nombre testé est inférieure au
              nombre premier actuel,inutile de continuer le test*/
            if(nb_premier>sqrt(test))
            {borne=1;}
        }

        fclose(fichier);
        if(borne==1)
        {return 1;}
    }
    return 0;
}

Illustration: illustrer.fr