IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Affecter des valeurs d'un fichier .csv à un vector de type class


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut Affecter des valeurs d'un fichier .csv à un vector de type class
    Bonjour,

    Serait-il possible de récupérer les valeurs du fichier .csv dans un vector de type class ? (sans parler du problème de conversion des string en int ou double) . C'est surtout la difficulté d'affecter "cell" à un membre de la class qui m'interroge...

    Ou suis-je obligé de repartir avec un 'bête' tableau double entrée ?

    Merci de votre aide,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
     
    class Tableau{
    public:
    	string colA;
    	int colB;
    	int colC;
    	double colD;
    	int colE;
    	Tableau (string A, int B, int C, double D, int E)
    		:colA(A), colB(B), colC(C), colD(D), colE(E) { }
    };
     
    int Ouverture(string nom_fichier){
     
    	ifstream fichier;										
     
    	string chemin = nom_fichier + ".csv" ;					
     
    	fichier.open(chemin.c_str());							
     
    	if (!fichier){											
    		cout << "Erreur lors de l'ouverture du fichier " 
    			 << chemin
    			 << endl;
    		system ("PAUSE");
    		exit(1);
    	}
     
    	string ligne;
    	int nb_lignes = 0;
    	vector<Tableau>table;
     
    	while (getline(fichier, ligne)){
    		stringstream lineStream(ligne);
    		string cell;
    		int nb_cell = 0;
    		if (nb_lignes > 0){
    			while (getline(lineStream, cell, ';')){
    				if (cell == "")
    					cell = "0";
    				++nb_cell;
    				cout << nb_cell << " " << cell << "\t";
    			}
    		}
    		cout << endl;
     
    		++nb_lignes;
    	}
     
    	fichier.close();										
     
    	return nb_lignes;									
    }

  2. #2
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Salut, bienvenue sur le forum

    Tout d'abord, dans ta classe Tableau, il manque un destructeur. Il faudrait aussi que tu penses à mettre tes attributs dans le private...

    L'algo est "assez" simple :

    1) tu parses ta ligne avec le délimiteur ";" -> regarde du côyé de find() et substr qui sont 2 fonctions membres de std::string
    2) tu récupères les donnés, tu les convertis en int ou double -> sur ce forum il y a tout ce qu'il te faut
    3) tu utilises des setters pour assigner une valeurs à tes attributs

  3. #3
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut
    Merci pour ces éléments.

    Les points 1) et 2) sont OK, mais c'est le 3) qui me pose toujours problème... je regarde du côté getter-setter

  4. #4
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut
    Bon finalement il y a cette solution qui fonctionne, mais j'ai l'impression de faire du C ... N'existe-t-il pas une solution plus concise, notamment pour éviter de multiplier les vector ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
     
    int Ouverture(string nom_fichier){
     
    	ifstream fichier;										
     
    	string chemin = nom_fichier + ".csv" ;					
     
    	fichier.open(chemin.c_str());							
     
    	if (!fichier){											
    		cout << "Erreur lors de l'ouverture du fichier " 
    			 << chemin
    			 << endl;
    		system ("PAUSE");
    		exit(1);
    	}
     
    	string ligne;
    	int nb_lignes = 0; 
     
    	vector<string>colA;  /* Chaque vector contient 1 colonne du fichier */
    	vector<int>colB;
    	vector<int>colC;
    	vector<double>colD;
    	vector<int>colE;
     
    	while (getline(fichier, ligne)){   /* Lit chaque ligne */
     
    		stringstream fluxLigne(ligne);
    		string cell;
    		int nb_cell = 0;
     
    		if (nb_lignes > 0){
    			while (getline(fluxLigne, cell, ';')){   /* Lit chaque cellule */
    				if (cell == "")        /* Comble les cellules vides */
    					cell = "0";
    				switch (nb_cell){  /* Remplit les colonnes successives */
    					case 0:
    						colA.push_back(cell);
    						break;
    					case 1:
    						colB.push_back(atoi(cell.c_str()));
    						break;
    					case 2:
    						colC.push_back(atoi(cell.c_str()));
    						break;
    					case 3:
    						colD.push_back(atof(cell.c_str()));
    						break;
    					case 4:
    						colE.push_back(atoi(cell.c_str()));
    						break;
    				}
    				++nb_cell;
    			}
    		}
    		++nb_lignes;
    	}
     
    	fichier.close();										
     
    	return nb_lignes;									
    }

  5. #5
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Salut,

    Citation Envoyé par salseropom Voir le message
    Tout d'abord, dans ta classe Tableau, il manque un destructeur.
    Pas besoin de destructeur, le compilateur le génère, cf. cette entrée de la FAQ.

    Citation Envoyé par dasycarpum Voir le message
    N'existe-t-il pas une solution plus concise, notamment pour éviter de multiplier les vector ?
    C'est difficile à dire sans savoir ce que tu comptes faire de tes données après les avoir chargées...

    MAT.

  6. #6
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut
    Citation Envoyé par Mat007 Voir le message

    C'est difficile à dire sans savoir ce que tu comptes faire de tes données après les avoir chargées...

    MAT.
    Essentiellement des stat (tri, moyenne, variance, somme, ...) : mon fichier .csv fait 88 colonnes (et 1,5 millions lignes !), donc pour traiter les données et les passer d'une fonction à l'autre, je voudrais juste éviter le passage de 88 vector individuels en paramètres... mais plutôt passer 1 objet avec 88 variables.

    Est-il possible de construire une class avec des vectors comme attributs ? et si oui, comment push_backer ces derniers ? Les traitements statistiques peuvent-ils alors être directement intégrés comme méthodes de la class ? (ben oui, quand on vient du C, on a un peu de mal...)

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Salut,

    si tu ne souhaites faire QUE des moyennes, écarts-types, variance etc... utilises Excel... (surtout si tu ne fais ces calculs qu'une seule fois)

    Maintenant, si ces moyennes, variances etc... sont ensuite des inputs pour d'autres fonctions (ou si tu as des tonnes et des tonnes de fichiers csv, alors OK pour du C++

    Pour répondre à tes questions :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    std::vector<double> v;
     
    v.push_bach(7.); // rajoute 7 à la fin de ton vector
    De mémoire (à confirmer !), il n'existe pas de fonction "moyenne", "variance" dans la STL. Mais bon, tu peux recoder ces fonctions (qui ne font que qq lignes), ou bien pour la moyenne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    double moyenne = std::accumulate(v.begin(), v.end(), 0.) / v.size();
    pour la moyenne, il existe des algo qui sont plus "solides" numériquement que la méthode que je viens de te citer.

    Il y a aussi tout ce qui est Boost, Lapack etc... si tu veux faire du calcul scientifique


    Pour continuer, tu disais :

    mon fichier .csv fait 88 colonnes (et 1,5 millions lignes !), donc pour traiter les données et les passer d'une fonction à l'autre, je voudrais juste éviter le passage de 88 vector individuels en paramètres... mais plutôt passer 1 objet avec 88 variables.

    => tu peux faire un simple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    std::vector<std::vector<double> > v;
    qui contiendra une "matrice". Ensuite, tu peux faire un enum

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    enum
    {
      NOMCOL1,
      NOMCOL2,
      NOMCOL3,
    etc..
     
      NBCOL // nombre total de colonnes (ne rien ecrire en dessous)
    } Index;
    avec cet enum, ton code sera plus lisible, et si demain tu intercales une nouvelle colonne entre 2 colonnes déjà existantes, tu n'auras rien à changer dans ton code déjà existant.

    Bon courage

  8. #8
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut
    Citation Envoyé par salseropom Voir le message
    Salut,

    si tu ne souhaites faire QUE des moyennes, écarts-types, variance etc... utilises Excel... (surtout si tu ne fais ces calculs qu'une seule fois)
    Sous Excel, j'ai mis 3 heures à traiter les données... codé en C, le traitement a pris 30 secondes... Je me suis mis au C++ pour associer plus facilement des graphiques.


    Citation Envoyé par salseropom Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    enum
    {
      NOMCOL1,
      NOMCOL2,
      NOMCOL3,
    etc..
     
      NBCOL // nombre total de colonnes (ne rien ecrire en dessous)
    } Index;
    avec cet enum, ton code sera plus lisible, et si demain tu intercales une nouvelle colonne entre 2 colonnes déjà existantes, tu n'auras rien à changer dans ton code déjà existant.
    C'est ce que je cherchais !

    Un grand merci Salseropom

  9. #9
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut Alternative...
    Citation Envoyé par dasycarpum Voir le message

    Un grand merci Salseropom
    La solution proposée implique néanmoins que toutes les colonnes du fichier aient le même type, ici 'double', or ce n'est pas toujours le cas...

    A la réflexion, on peut aussi passer par une struct (qui est finalement une class où tous les membres sont publics, ce qui est plutôt bien adapté pour des données brutes qui sont amenées à être constamment modifiées) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
     
    struct Data{      /* Création d'une structure correspondant à l'architecture du fichier .csv */
    	string colA;
    	int colB;
    	int colC;
    	double colD;
    	int colE;
    };
     
    int Ouverture(string nom_fichier){
     
    	ifstream fichier;	  /* Ouverture du fichier... */									
     
    	string chemin = nom_fichier + ".csv" ;					
     
    	fichier.open(chemin.c_str());				
     
    	if (!fichier){											
    		cout << "Erreur lors de l'ouverture du fichier " 
    			 << chemin
    			 << endl;
    		system ("PAUSE");
    		exit(1);
    	}
     
    	string ligne;
    	int nb_lignes = 0;
    	int max_colonne = 0;
     
    	vector<Data>tableau;    /* Création d'un vector du type de la structure */
    	Data donnees;              /* Création d'une variable du même type */
            donnees.colA = "aa"; donnees.colB = 0;  /*et son initialisation */
            donnees.colC = 0;donnees.colD = 0;donnees.colE = 0;
     
    	int nb_cell = 0;
     
    	while (getline(fichier, ligne)){  /* Lit une ligne du fichier */
     
    		stringstream fluxLigne(ligne);
    		string cell;
    		nb_cell = 0;
     
    		if (nb_lignes > 0){        /* Passe la ligne de titres des colonnes */
    			while (getline(fluxLigne, cell, ';')){  /* Lit cellule par cellule sur la ligne */
    				if (cell == "")
    					cell = "0";
    				switch (nb_cell){
    					case 0:
    						donnees.colA = cell; /* Affecte la cellule à la variable de type structure */
    						tableau.push_back(donnees); /* Ajoute la donnée ainsi récupérée au vector de type structure */
    						break;
    					case 1:
    						donnees.colB = atoi(cell.c_str()); /* idem avec conversion string en int */
    						tableau.push_back(donnees);
    						break;
    					case 2:
    						donnees.colC = atoi(cell.c_str());
    						tableau.push_back(donnees);
    						break;
    					case 3:
    						donnees.colD = atof(cell.c_str());
    						tableau.push_back(donnees);
    						break;
    					case 4:
    						donnees.colE = atoi(cell.c_str());
    						tableau.push_back(donnees);
    						break;
    				}
    				++nb_cell;
    				if (nb_cell > max_colonne)  /* Calcul du nombre de colonnes */
    					max_colonne = nb_cell;
    			}
    		}
    		++nb_lignes;
    	}
            /* Pour récupérer les données stockées dans vector */
    	for (int i = 0; i < (nb_lignes-1)*max_colonne ; i += max_colonne)
    		cout << tableau[i].colA << "\t" << tableau[i+1].colB << "\t" << tableau[i+2].colC << "\t" << tableau[i+3].colD << "\t" << tableau[i+4].colE << endl;
     
    	fichier.close();									
     
    	return nb_lignes;									
    }

  10. #10
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut Dernière question...
    Citation Envoyé par dasycarpum Voir le message
    A la réflexion, on peut aussi passer par une struct
    Après optimisation - 1 seul push_back suffit, et l'accès au tableau n'en est que facilité - on obtient ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
     
    struct Data{
    	string colA;
    	int colB;
    	int colC;
    	double colD;
    	int colE;
    };
     
    int Ouverture(string nom_fichier){
     
    	ifstream fichier;										
     
    	string chemin = nom_fichier + ".csv" ;					
     
    	fichier.open(chemin.c_str());							
     
    	if (!fichier){											
    		cout << "Erreur lors de l'ouverture du fichier " 
    			 << chemin
    			 << endl;
    		system ("PAUSE");
    		exit(1);
    	}
     
     
    	string ligne;
    	int nb_lignes = 0;
     
     
    	vector<Data>tableau;
    	Data donnees; donnees.colA = "aa"; donnees.colB = 0; donnees.colC = 0;donnees.colD = 0;donnees.colE = 0;
     
    	while (getline(fichier, ligne)){
     
    		stringstream fluxLigne(ligne);
    		string cell;
    		int nb_cell = 0;
     
    		if (nb_lignes > 0){
    			while (getline(fluxLigne, cell, ';')){
    				if (cell == "")
    					cell = "0";
    				switch (nb_cell){
    					case 0:
    						donnees.colA = cell;
    						break;
    					case 1:
    						donnees.colB = atoi(cell.c_str());
    						break;
    					case 2:
    						donnees.colC = atoi(cell.c_str());
    						break;
    					case 3:
    						donnees.colD = atof(cell.c_str());
    						break;
    					case 4:
    						donnees.colE = atoi(cell.c_str());
    						break;
    				}
    				++nb_cell;
    			}
    			tableau.push_back(donnees);
    		}
    		++nb_lignes;
    	}
     
            /* Accès au tableau */
            for (int i = 0; i < nb_lignes-1 ; ++i )
    		cout << tableau[i].colA << "\t" << tableau[i].colB << "\t" << tableau[i].colC << "\t" << tableau[i].colD << "\t" << tableau[i].colE << endl;
     
    	fichier.close();										
     
    	return nb_lignes;									
    }
    Il me reste néanmoins une dernière question : ce code de 50 lignes en C++ a pourtant l'air simple et concis MAIS pour lire la totalité de mon fichier .csv de 547 Mo, cela prend 179 secondes, alors qu'un code en C (de 200 lignes) me le lit en 41 secondes sur la même machine. [Par contre, pour la gestion de la mémoire c'est l'inverse : 250 Mo nécessaires en C++ (car tout n'a pas besoin d'être lu) et 1 Go en C ! ]

    Vaut-il donc mieux coder certaines fonctions en C dans un programme en C++ ?

    Merci pour votre éclairage

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    ce qui doit être long est que tu fais des push_back à gogo. Le principe d'un std::vector est que les éléments doivent être contigus. Si tu fais un push_back et que l'espace mémoire n'est plus assez grand, alors toutes les données seront recopiées vers un autre espace mémoire plus grand.

    Solution : essaye de déterminer dès le début du programme le nombre de ligne. Tu as ainsi le nombre de data à lire. Tu fais un gros resize() et finis les copies temporaires.

    De toute manière, un std::vector<T> n'est rien d'autre qu'un simple T *

    Ciao

  12. #12
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut
    Citation Envoyé par salseropom Voir le message

    Solution : essaye de déterminer dès le début du programme le nombre de ligne. Tu as ainsi le nombre de data à lire. Tu fais un gros resize() et finis les copies temporaires.

    De toute manière, un std::vector<T> n'est rien d'autre qu'un simple T *

    Ciao
    OK merci, je vais essayer, ça ne devrait pas poser de problèmes.

    Bonne soirée

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 26/03/2014, 16h30
  2. Réponses: 2
    Dernier message: 07/06/2012, 13h11
  3. [MySQL] Importer des valeurs "date" depuis fichier csv
    Par all42 dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 27/05/2007, 11h23
  4. [VBA-E] Lire des valeurs dans un fichier excel
    Par nicobox dans le forum Macros et VBA Excel
    Réponses: 7
    Dernier message: 11/05/2006, 16h40
  5. [VB]vérifier des valeurs dans un fichiers et trier
    Par Mut dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 16/02/2006, 18h35

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo