Comparaison et calculs sur deux fichiers à la fois

Comparaison et calculs sur deux fichiers à la fois - Perl - Programmation

Marsh Posté le 18-09-2012 à 11:42:37    

Bonjour,
 
j'ai un nouveau problème  :(.
 
Je me demande s'il est possible de mettre en "lien" deux fichiers (ou tableaux) et faire des calculs dessus?
 
Explication:
Mon premier fichier 'france1_calendrier_csv.txt' est de la forme:

Spoiler :

6;2012-09-21;20:45:00;Montpellier ;St Etienne
6;2012-09-22;17:00:00;Bastia ;Paris SG
6;2012-09-22;20:00:00;Brest ;Valenciennes
6;2012-09-22;20:00:00;Lorient ;Nice
6;2012-09-22;20:00:00;Reims ;Nancy
6;2012-09-22;20:00:00;Sochaux ;Troyes
6;2012-09-22;20:00:00;Toulouse ;Rennes
6;2012-09-23;14:00:00;Bordeaux ;Ajaccio
6;2012-09-23;17:00:00;Marseille ;Evian TG
6;2012-09-23;21:00:00;Lille ;Lyon
 
7;2012-09-28;20:45:00;Rennes ;Lille
7;2012-09-29;17:30:00;Paris SG ;Sochaux
7;2012-09-29;19:00:00;Ajaccio ;Brest
7;2012-09-29;19:00:00;Evian TG ;Lorient
7;2012-09-29;19:00:00;Nancy ;Montpellier
7;2012-09-29;19:00:00;Nice ;Bastia
7;2012-09-29;19:00:00;Troyes ;Toulouse
7;2012-09-30;14:00:00;Valenciennes ;Marseille
7;2012-09-30;17:00:00;St Etienne ;Reims
7;2012-09-30;21:00:00;Lyon ;Bordeaux
 
8;2012-10-06;19:00:00;Bastia ;Troyes
8;2012-10-06;19:00:00;Brest ;Bordeaux
8;2012-10-06;19:00:00;Lille ;Ajaccio
8;2012-10-06;19:00:00;Lorient ;Lyon
8;2012-10-06;19:00:00;Marseille ;Paris SG
8;2012-10-06;19:00:00;Montpellier ;Evian TG
8;2012-10-06;19:00:00;Reims ;Nice
8;2012-10-06;19:00:00;Sochaux ;Rennes
8;2012-10-06;19:00:00;St Etienne ;Nancy
8;2012-10-06;19:00:00;Toulouse ;Valenciennes
 
...
...


 
Et mon deuxième fichier 'france1_forces_global_M1.txt' est de la forme:

Spoiler :

Ajaccio ;0.25;0.59;0;0.14
Bastia ;0.26;0.94;0.61;0.74
Bordeaux ;0.24;0.24;0.15;0.42
Brest ;0.39;1.08;0.14;0.28
Evian TG ;0.72;0.37;0.55;0
Lille ;0.24;0.47;0.46;0.73
Lorient ;0.62;0.62;0.15;0.84
Lyon ;1.05;0.13;0.43;0.29
Marseille ;0.57;0;0.15;0.42
Montpellier ;0.12;0.7;0.3;0.71
Nancy ;0.12;0.46;0.28;0.14
Nice ;0.7;0.12;0.7;0.15
Paris SG ;0.46;0.12;0.28;0.28
Reims ;0.48;0.36;0.28;0.28
Rennes ;0.49;0.49;0.7;0.15
Sochaux ;0.36;0.36;0.84;0.15
St Etienne ;0.59;0.25;0.45;0.58
Toulouse ;0.36;0.36;0.28;0.28
Troyes ;0.37;0.72;0.57;0.3
Valenciennes ;0.36;0.36;0;0.41


 
 
Alors le but (c'est un peu compliqué mais je vais essayé d'être clair) c'est de faire des calculs pour chaque matchs du calendrier(plus particulièrement pour 2 journées, ici en l'occurence pour les journées 6 et 7 qui sont les premiers champs du fichier 'france1_calendrier_csv.txt' et une fois que la journée 6 est passé il faudrait que mon script fasse les calculs pour les journées 7 et 8). Les calculs sont en fait de simples multiplications mais sur des champs particuliers suivant qu'une équipe joue à domicile ou à l'extérieur, par exemple pour le premier match de la 6ème journée Montpellier - St Etienne il y a deux calculs à réaliser. Le 1er est $coeff1=0.12*0.25=0.03 et le deuxième est $coeff2=0.3*0.58=0.174, en fait pour ces deux calculs il faut que j'arrive à récupérer sur la ligne de Montpellier les valeurs du 2ème et 4ème champ(0.12 et 0.3) et sur la ligne de St Etienne les valeurs du 3ème et 5ème champ(0.25 et 0.58). Pour le match suivant Bastia - Paris SG il faudrait donc $coeff1=0.26*0.12=0.0312 et $coeff2=0.61*0.28=0.1708 ....
 
J'ai essayé avec deux tableaux et des boucles for mais sans succès, c'est vite le bordel dans les boucles et ça me sort n'importe quoi ! Je me suis dit que peut-être travailler avec des Hashs serait la solution mais je n'arrive pas à construire un hash issu de ces deux fichiers qui aurait la structure suivante ->
 
%matchs = { 'Montpellier - St Etienne'  => { 'Montpellier' => '0.03',  
                                                                      'St Etienne' => '0.174' },  
                      'Bastia - Paris SG' => { 'Bastia' => '0.0312',  
                                                          'PSG' => '0.1708' },  
                      'Brest - Valenciennes' => { 'Brest' => '0.1404',  
                                                                'Valenciennes' => '0.0574' },  
.........
.........
}  
 
Du coup avec une structure comme celle-ci j'aurais accès très facilement aux matchs, aux équipes et aux valeurs dont j'ai besoin pour faire des calculs de probabilités, là se serait le top.
 
Si vous avez une piste sur comment on peut manipuler deux fichiers différents je suis preneur .... merci.
 
A+

Reply

Marsh Posté le 18-09-2012 à 11:42:37   

Reply

Marsh Posté le 18-09-2012 à 12:14:35    

:hello: Je vais finir par penser que tu bosses pour un site de paris en ligne :D
Je vais bouffer la, je regarde ça cet après midi.
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 18-09-2012 à 15:44:59    

Voila ce qui devrait te convenir:

Code :
  1. #!/usr/local/bin/perl
  2. use strict;
  3. use warnings;
  4. use autodie;
  5.  
  6. use Data::Dumper;
  7.  
  8. my %coefs;
  9. open(my $IN, 'france1_forces_global_M1.txt');
  10. while (<$IN> ) {
  11.  chomp;
  12.  my @fields = split /;/;
  13.  next if (@fields < 5);
  14.  map {s/^\s*|\s*$//g} @fields;
  15.  $coefs{lc($fields[0])} = [@fields[1..4]];
  16. }
  17. close($IN);
  18.  
  19. my %matches;
  20. use constant START_WEEK => 6;
  21. open($IN, 'france1_calendrier_csv.txt');
  22. while (<$IN> ) {
  23.  chomp;
  24.  my @fields = split /;/;
  25.  next if (@fields < 5);
  26.  map {s/^\s*|\s*$//g;} @fields;
  27.  next if ($fields[0] < START_WEEK or $fields[0] > (1 + START_WEEK));
  28.  $matches{"$fields[3] - $fields[4]"} = {
  29.                      $fields[3] => $coefs{lc($fields[3])}->[0] * $coefs{lc($fields[4])}->[1],
  30.                      $fields[4] => $coefs{lc($fields[3])}->[2] * $coefs{lc($fields[4])}->[3],};
  31. }
  32. close($IN);
  33.  
  34. print Dumper(%matches);


 

$VAR1 = 'Valenciennes - Marseille';
$VAR2 = {
          'Marseille' => '0',
          'Valenciennes' => '0'
        };
$VAR3 = 'Evian TG - Lorient';
$VAR4 = {
          'Evian TG' => '0.4464',
          'Lorient' => '0.462'
        };
$VAR5 = 'Ajaccio - Brest';
$VAR6 = {
          'Ajaccio' => '0.27',
          'Brest' => '0'
        };
$VAR7 = 'Bordeaux - Ajaccio';
$VAR8 = {
          'Ajaccio' => '0.021',
          'Bordeaux' => '0.1416'
        };
$VAR9 = 'Lorient - Nice';
$VAR10 = {
           'Nice' => '0.0225',
           'Lorient' => '0.0744'
         };
$VAR11 = 'Brest - Valenciennes';
$VAR12 = {
           'Brest' => '0.1404',
           'Valenciennes' => '0.0574'
         };
$VAR13 = 'Montpellier - St Etienne';
$VAR14 = {
           'St Etienne' => '0.174',
           'Montpellier' => '0.03'
         };
$VAR15 = 'St Etienne - Reims';
$VAR16 = {
           'Reims' => '0.126',
           'St Etienne' => '0.2124'
         };
$VAR17 = 'Lyon - Bordeaux';
$VAR18 = {
           'Bordeaux' => '0.1806',
           'Lyon' => '0.252'
         };
$VAR19 = 'Bastia - Paris SG';
$VAR20 = {
           'Paris SG' => '0.1708',
           'Bastia' => '0.0312'
         };
$VAR21 = 'Paris SG - Sochaux';
$VAR22 = {
           'Paris SG' => '0.1656',
           'Sochaux' => '0.042'
         };
$VAR23 = 'Lille - Lyon';
$VAR24 = {
           'Lille' => '0.0312',
           'Lyon' => '0.1334'
         };
$VAR25 = 'Nice - Bastia';
$VAR26 = {
           'Nice' => '0.658',
           'Bastia' => '0.518'
         };
$VAR27 = 'Marseille - Evian TG';
$VAR28 = {
           'Marseille' => '0.2109',
           'Evian TG' => '0'
         };
$VAR29 = 'Troyes - Toulouse';
$VAR30 = {
           'Toulouse' => '0.1596',
           'Troyes' => '0.1332'
         };
$VAR31 = 'Nancy - Montpellier';
$VAR32 = {
           'Nancy' => '0.084',
           'Montpellier' => '0.1988'
         };
$VAR33 = 'Rennes - Lille';
$VAR34 = {
           'Lille' => '0.511',
           'Rennes' => '0.2303'
         };
$VAR35 = 'Toulouse - Rennes';
$VAR36 = {
           'Toulouse' => '0.1764',
           'Rennes' => '0.042'
         };
$VAR37 = 'Reims - Nancy';
$VAR38 = {
           'Nancy' => '0.0392',
           'Reims' => '0.2208'
         };
$VAR39 = 'Sochaux - Troyes';
$VAR40 = {
           'Troyes' => '0.252',
           'Sochaux' => '0.2592'
         };


C'est un dump de la structure pour te montrer qu'elle contient ce que tu veux, à toi de l'utiliser comme il te convient.
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 18-09-2012 à 15:55:44    

QQues explications sur le code:
$coefs{lc($fields[0])} = [@fields[1..4]];
coefs est un hash qui va avoir comme clé le nom de la ville et comme valeur un tableau contenant les 4 coeffs.
$coeffs{'sochaux'}->[2] est donc le 3e coeff pour Sochaux.
Noter que je passe les noms en minuscules dans la clé, avec lc, afin qu'on n'ait pas de pb avec le format des données de l'autre fichier (on est jamais sur que ce soit totalement identique).
 
$matches{"$fields[3] - $fields[4]"} = {
                     $fields[3] => $coefs{lc($fields[3])}->[0] * $coefs{lc($fields[4])}->[1],
                     $fields[4] => $coefs{lc($fields[3])}->[2] * $coefs{lc($fields[4])}->[3]};
 
matches est un hash qui a pour clé les noms des matches, construit à partir du des noms des deux villes/clubs, et pour valeur un autre hash, qui a pour clés les noms des des deux villes, et valeurs associées les valeurs calculées à partir de ce qui a été stocké dans %coeffs.
 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 18-09-2012 à 17:42:32    

:jap:  Super, ça marche nickel ! En quelques lignes t'as résolu le truc, trop fort !!
 
je vais regarder ça de plus près pour retirer les bonnes infos.
 
Par contre dans la ligne -> use constant START_WEEK => 6;
 
est-ce qu'il est possible d'utiliser une variable préalablement calculée à la place de 6, car cette valeur est amenée à être modifiée chaque fin de journée ? par exemple si je met $nb_journee qui vaut 7, ça marchera ?
 
Merci à toi


Message édité par thales69 le 18-09-2012 à 17:45:00
Reply

Marsh Posté le 18-09-2012 à 19:21:49    

Tu peux tout à fait remplacer par une variable.
 

Code :
  1. #!/usr/local/bin/perl
  2. use strict;
  3. use warnings;
  4. use autodie;
  5.  
  6. use Data::Dumper;
  7.  
  8. my $week_number = 6;
  9.  
  10. my %coefs;
  11. open(my $IN, 'france1_forces_global_M1.txt');
  12. while (<$IN> ) {
  13.  chomp;
  14.  my @fields = split /;/;
  15.  next if @fields < 5;
  16.  map {s/^\s*|\s*$//g} @fields;
  17.  $coefs{lc($fields[0])} = [@fields[1..4]];
  18. }
  19. close($IN);
  20.  
  21. my %matches;
  22. open($IN, 'france1_calendrier_csv.txt');
  23. while (<$IN> ) {
  24.  chomp;
  25.  my @fields = split /;/;
  26.  next if @fields < 5;
  27.  map {s/^\s*|\s*$//g;} @fields;
  28.  next if $fields[0] < $week_number or $fields[0] > (1 + $week_number);
  29.  my ($hometeam, $visitors) = @fields[3,4];
  30.  next unless exists $coefs{lc($hometeam)} and exists $coefs{lc($visitors)};
  31.  $matches{"$hometeam - $visitors"} = {
  32.                      $hometeam => $coefs{lc($hometeam)}->[0] * $coefs{lc($visitors)}->[1],
  33.                      $visitors => $coefs{lc($hometeam)}->[2] * $coefs{lc($visitors)}->[3]};
  34. }
  35. close($IN);
  36.  
  37. print Dumper(%matches);


la ligne  
next unless exists $coefs{lc($hometeam)} and exists $coefs{lc($visitors)};
blinde le code au cas ou il y aurait un nom différent entre les deux fichiers.
 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 18-09-2012 à 22:05:15    

Merci pour les explications Gilou, juste une dernière question sur le code, que veut dire la ligne  -> next if @fields<5;
@fields est bien un tableau, comment peut-on le comparer à un nombre? et quelle est la signification de 5 ?

Reply

Marsh Posté le 18-09-2012 à 22:11:43    

Dans ce contexte, @fields représente le nombre d'élements dans le tableau.
 
C'est donc "ne pas passer dans la boucle si il y a moins de 5 éléments dans le tableau @fields, et traiter la ligne suivante"
 
Normalement, on utilise $fields pour compter le nombre d'éléments dans le tableau, la le cast est implicite vu qu'il compare le tableau à un scalaire.

Reply

Marsh Posté le 18-09-2012 à 22:17:24    

Merci ccp6128 pour les précisions.

Reply

Marsh Posté le 19-09-2012 à 17:40:15    

Salut,
 
alors le script marche super bien, par contre j'essaie de l'utiliser en l'incluant dans une fonction. Comme je veux que tout soit automatisé (et donc que je n'ai pas à écrire à chaque fois le nom des équipes) j'ai mis dans un tableau @versus les champs de mon fichier "france1_calendrier_csv_temp.txt" pour pouvoir utiliser dynamiquement les noms des équipes qui jouent l'une contre l'autre. Mais quand j'essaie d'atteindre la valeur $matches{'Montpellier - St Etienne'}{'Montpellier'} calculée dans le hash %matches
avec la syntaxe suivante $matches{'$versus[$l][3] - $versus[$l][4]'}{'$versus[$l][3]'} dans une boucle for($l=0; $l<=$nb_matchs; $l++) j'ai une erreur du type "Use of uninitialized value in concatenation (.) or string".
 
Est-ce qu'il est possible d'utiliser des variables comme je l'ai fait pour récupérer la valeur de la clef d'un hash ? J'ai rien vu à ce sujet sur le net ... j'espère que c'est possible sinon je suis dans la mouise :).
 
Et autre question est-ce qu'il est possible de construire un hash de hash avec des boucles for ?
 
A+

Message cité 1 fois
Message édité par thales69 le 19-09-2012 à 18:05:49
Reply

Marsh Posté le 19-09-2012 à 17:40:15   

Reply

Marsh Posté le 19-09-2012 à 18:51:41    

thales69 a écrit :

Salut,
 
alors le script marche super bien, par contre j'essaie de l'utiliser en l'incluant dans une fonction. Comme je veux que tout soit automatisé (et donc que je n'ai pas à écrire à chaque fois le nom des équipes) j'ai mis dans un tableau @versus les champs de mon fichier "france1_calendrier_csv_temp.txt" pour pouvoir utiliser dynamiquement les noms des équipes qui jouent l'une contre l'autre. Mais quand j'essaie d'atteindre la valeur $matches{'Montpellier - St Etienne'}{'Montpellier'} calculée dans le hash %matches
avec la syntaxe suivante $matches{'$versus[$l][3] - $versus[$l][4]'}{'$versus[$l][3]'} dans une boucle for($l=0; $l<=$nb_matchs; $l++) j'ai une erreur du type "Use of uninitialized value in concatenation (.) or string".
 
Est-ce qu'il est possible d'utiliser des variables comme je l'ai fait pour récupérer la valeur de la clef d'un hash ? J'ai rien vu à ce sujet sur le net ... j'espère que c'est possible sinon je suis dans la mouise :).
 
Et autre question est-ce qu'il est possible de construire un hash de hash avec des boucles for ?
 
A+

1) Faut pas mettre de simples quotes dans $matches{'$versus[$l][3] - $versus[$l][4]'}{'$versus[$l][3]'} si tu veux que les variables $xxx soient interprétées, mais des doubles comme dans mon code.
2) tu veux dire utiliser une variable comme clé pour récupérer le value d'un hash, non? c'est ce que je fais dans mon code
3) pourquoi pas.
A+,


Message édité par gilou le 19-09-2012 à 18:53:21

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 19-09-2012 à 23:16:05    

1) j'avais essayé avec les doubles quotes mais sans succès, $matches{"$versus[0][3] - $versus[0][4]"}{"$versus[0][3]"}; me renvoie  la même erreur "Use of uninitialized value in print at essai2.pl line 132." alors qu'un print de $versus[0][3] ou de $versus[0][4] fonctionne parfaitement. Je comprend pas où est l'erreur pour le moment.
 
2) oui c'est exactement ça. ça marche très bien dans ton code mais pour moi $matches{"$versus[0][3] - $versus[0][4]"}{"$versus[0][3]"} n'est pas interprété et encore moins $matches{"$versus[$l][3] - $versus[$l][4]"}{"$versus[$l][3]"} !
 
3) je vais essayé alors ... si bien sûr j'arrive déjà à faire sortir une valeur à $matches{"$versus[$l][3] - $versus[$l][4]"}{"$versus[$l][3]"}
 
 
.... bon ben je me remet à nouveau à la recherche de ce qui cloche, je vais bien finir par trouver !
 
a+


Message édité par thales69 le 19-09-2012 à 23:27:29
Reply

Marsh Posté le 19-09-2012 à 23:52:46    

Désolé, pour le 1) et 2) c'est bon, en construisant @versus j'avais enlevé des espaces sur les lignes du fichier csv et du coup St Etienne était devenu StEtienne et ça ne matchait plus avec les clés du hash .... c'était devant mon pif depuis cette après-midi et j'avais pas vu ! Une belle connerie de débutant !
Me reste plus qu'à essayer de construire ce hash de hash avec des boucles .... vaste programme.
Gilou, merci pour l'info des doubles quotes, ça m'a bien aiguillé dans ma recherche :)
a+


Message édité par thales69 le 20-09-2012 à 08:28:49
Reply

Marsh Posté le 21-09-2012 à 00:26:55    

:hello:  
Je n'étais pas la de la journée.
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed