Results 1 to 8 of 8

Thread: [RESOLVED] Pipe "|" delimited file into separate variables to insert into linked list

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Aug 2012
    Posts
    75

    Resolved [RESOLVED] Pipe "|" delimited file into separate variables to insert into linked list

    Hi!
    Well this is a nutcracker for me.
    I am trying to do something useful while learning single linked list in c++

    First I have a | delimited file with contents like this:

    Code:
    John Doe|M|25
    Jane Doe|F|21
    Jack Smith|M|40
    Jessica Hunt|F|30
    I want to read that file line by line into separate variables.
    I've made a class for reading and writing to a file like this:

    Code:
    class FileOperations {
        
      public:
      	
        void fileToList (string fileName){
    	    ifstream inputFile(fileName);
    	    string line;
    	    
    	    string name;
    	    char gender;
    	    int age;
    	    
    	    	 
    	    /* While there is still a line. */
    	    while(getline(inputFile, line, '|')) {
    	        /* Printing goes here. */
    	        
    	        cout << line;
    	        cout << gender;
    	        cout << age << endl;
    	        
    	        	        
    	    }
    	 	
    	    inputFile.close();
    		}	
        
    	void listToFile (string fileName, string data){
        	
    		ofstream outputFile;
    		outputFile.open(fileName);
    		
    		outputFile << data << endl;
    		
    		outputFile.close();
    			
    	}
    
    };
    How can I modify the readFile so it stores values based on delimiter "|" like so:

    string name; -> John Doe
    char gender; -> M
    int age; -> 25

    I want to pass these variables later on to a linked list via Append function.

    My linked list program (not finished) is this:
    Code:
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class Node {
    	public:
    		
    		string name;
    		char gender;
    		int age;
    		
    		Node *next;
    		
    		Node (string aName, char aGender, int aAge, Node *aNext){
    			name = aName;
    			gender = aGender;
    			age = aAge;
    			next = aNext;
    		}
    		
    		string getName() {
    			return name;
    		};
    		
    		char getGender() {
    			return gender;
    		};
    		
    		int getAge() {
    			return age;
    		};
    		
    		Node *Next() {
    			return next;
    		}
    		
    		void setNext (Node *aNext) {
    			next = aNext;
    		}
    };
    
    class LinkedList {
    	public:
    		Node *head;
    		LinkedList() {
    			head = NULL;
    		}
    		
    		void Append(string name, char gender, int age) {
    			Node *newNode = new Node(name, gender, age, NULL);
    			Node *tmp = head;
    			//Duplicates not allowed
    			//while(!Search(data)){ 
    				
    				if (tmp != NULL) {
    					while (tmp->Next() != NULL) {
    						tmp = tmp->Next();
    					}
    					tmp->setNext(newNode);
    				}
    				else {
    					head = newNode;
    				}
    			//}
    		}
    		
    		
    		/* Function to print out linked list */
    		void Print() {
    			Node *tmp = head;
    			if (tmp == NULL) {
    				cout << "The list is empty!" << endl;
    				return;
    			}
    			if (tmp->Next() == NULL) {
    				cout << tmp->getName() << " " << tmp->getGender() << " " << tmp->getAge();
    				cout << "-->";
    				cout << "NULL" << endl;
    			}
    			else {
    				do {
    					cout << tmp->getName() << " " << tmp->getGender() << " " << tmp->getAge();
    					cout << "-->";
    					tmp = tmp->Next();
    				} while (tmp != NULL);
    				cout << "NULL" << endl;
    			}
    		}
    
    		/* Function to remove single value from a linked list */
    		void Delete(string data) {
    			Node *tmp = head;
    						
    			if (tmp == NULL) {
    				return;
    			}
    			if (tmp->Next() == NULL) {
    				delete tmp;
    				head = NULL;
    				
    			}
    			else {
    				Node *prev;
    				do {
    					if (tmp->getName() == data)
    					break;
    					prev = tmp;
    					tmp = tmp->Next();
    				} while (tmp != NULL);
    				prev->setNext(tmp->Next());
    				delete tmp;
    				
    			}
    						
    		}		
    		
    		/* Function to remove duplicates from a unsorted linked list */
    		void removeDuplicates(string del) {
    			
    			Node *current = head;
    			Node *next_nd;
    			Node *prev;
     
       		while( current != NULL ){
     
    	      	next_nd = current->next;
    	      	prev = current;
     
    	      	while( next_nd != NULL && current->getName() == del ){
    	      		
    		         if( next_nd->name == current->name){
    		            prev->next = next_nd->next;
    		            delete next_nd;
    		            next_nd = prev->next;
    		         }
    		         else{
    		            prev = next_nd;
    		            next_nd = next_nd->next;
    		         }
    	      }
          		current = current->next;
          		
    			}
    		}
    		
    
    		/* DEPRECATED: Function to search for a single value form a linked list */
    		
    		/*void Search(string value) {
    		
    			Node *tmp = head;
    			int found = 0; //Hit counter
    			
    			//Traversing the list
    			while(tmp != NULL){
    				if(tmp->getName() == value){
    					cout << value << " found in the list!" << endl;
    					found++;
    				}
    				
    				tmp = tmp->Next();
    			}
    			//If no hits, then value was not found
    			if (found == 0){
    				cout << value << " was not found in the list!" << endl;
    			}
    			
    		}*/
    		
    		
    		/* Function to search for a single value form a linked list. Returns TRUE or FALSE */
    		bool Search(string value) {
    		
    			Node *tmp = head;
    			int found = 0; //Hit counter
    			
    			//Traversing the list
    			while(tmp != NULL){
    				if(tmp->getName() == value){
    					found++;
    					return true;
    				}
    				
    				tmp = tmp->Next();
    			}
    			//If no hits, then value was not found
    			if (found == 0){
    				return false;
    			}
    			
    		}
    		
    		
    };
    
    int menu()
    {
    int choice = 0;
    
    	do {
    		cout << "\nMenu\n" << endl;
    		cout << "[1] Add an item." << endl;
    		cout << "[2] Remove item(s)." << endl;
    		cout << "[3] Search from the list." << endl;
    		cout << "[4] Display the list of names." << endl;
    		cout << "[5] Quit.\n" << endl;
    		cout << "Your choice: ";
    
    		choice = 0;
    		if (!(cin >> choice) || (choice < 1) || (choice > 5)) {
    			cout << "Invalid choice. \nChoice needs to be in range 1 to 5" << endl;
    			cin.clear();
    			cin.ignore(1000, '\n');
    		}
    	} while (choice < 1 || choice > 5);
    
    	return choice;
    }
    		
    int main()
    {
    	
    	char gender;
    	string name;
    	int age;
    	int choice = 0;
    	
    	LinkedList names;
    	
    	do{
    		
    		
    		switch(choice = menu()){
    			
    			case 1: 	cout << "Please enter a name to add (CASE sensitive): ";
    						cin.ignore(1000, '\n');
    						getline (cin, name);
    						
    						while ((cout << "Insert gender (M/F): ") && (cin >> gender) && ((gender = toupper(gender)) != 'M' && gender != 'F')) {
    						cout << "Please answer M for Male or F for Female\n";
    						}
    						cout << "Insert age: ";
    						cin >> age;
    						names.Append(name, gender, age);
    						break;
    			
    			case 2:		cout << "Please enter a name to delete (CASE sensitive): ";
    						cin.ignore(1000, '\n');
    						getline (cin, name);
    						//names.removeDuplicates(name);
    						//TODO: Still need to work on that
    						break;
    						
    			case 3:		cout << "Please enter a name to search (CASE sensitive): ";
    						cin.ignore(1000, '\n');
    						getline (cin, name);
    						//names.Search(name);
    						break;
    			
    			case 4:		names.Print();
    						break;
    						
    			case 5:		break; //Not really necessary
    						
    			default:	cin.ignore();
    						getline (cin, name); //To prevent looping as many times as there is characters in input string
    						cout << "INVALID choice, try again!\n" << endl;
    						break;
    						
    		}
    		
    		
    	}while(choice != '5');
    	
    	return 0;
    }
    Any ideas how achieve this dynamically?
    Last edited by lkallas; Feb 2nd, 2015 at 02:03 PM.

  2. #2
    Fanatic Member 2kaud's Avatar
    Join Date
    May 2014
    Location
    England
    Posts
    996

    Re: Pipe "|" delimited file into separate variables to insert into linked list

    Well this is a nutcracker for me.
    Try this
    Code:
    #include <iostream>
    #include <iomanip>
    #include <fstream>
    #include <string>
    #include <sstream>
    #include <cctype>
    using namespace std;
    
    const char delim = '|';
    const int max_choice = 9;
    
    struct record
    {
    	string name;
    	char gender;
    	int age;
    
    	record() : name(""), gender(' '), age(0) {}
    
    	bool operator==(const record& rec)
    	{
    		return (rec.age == age && rec.gender == gender && rec.name == name);
    	}
    
    	bool operator!=(const record& rec) {
    		return !operator==(rec);
    	}
    };
    
    string trim(const string& st)
    {
    size_t f = st.find_first_not_of(' ');
    size_t l = st.find_last_not_of(' ');
    
    	return (f != string::npos && l != string::npos) ? st.substr(f, l - f + 1) : "";
    }
    
    istream& operator>> (istream& is, record& rec)
    {
    string st;
    record tmp;
    
    	rec.age = 0;
    	rec.name = "";
    	rec.gender = ' ';
    
    	if (getline(is, st)) {
    		stringstream ss;
    		string dt;
    
    		ss.str(st);
    		getline(ss, dt, delim);
    		tmp.name = trim(dt);
    		getline(ss, dt, delim);
    		tmp.gender = (char)toupper(trim(dt)[0]);
    		getline(ss, dt);
    		tmp.age = atoi(dt.c_str());
    
    		if (!is.fail())
    			rec = tmp;
    	}
    
    	return is;
    }
    
    ostream& operator <<(ostream& os, const record& rec)
    {
    	os << rec.name << delim << rec.gender << delim << rec.age;
    	return os;
    }
    
    class Node {
    	record data;
    	Node *next;
    
    public:
    	Node(const record& aData, Node* aNext = NULL) : data(aData), next(aNext) {}
    
    	record getData() const {
    		return data;
    	};
    
    	Node* Next() const {
    		return next;
    	}
    
    	Node* setNext(Node *aNext) {
    		next = aNext;
    		return next;
    	}
    };
    
    class LinkedList {
    	Node *head;
    
    public:
    	LinkedList() : head(NULL) {}
    
    	~LinkedList() {
    		Delete("", false, true);
    	}
    
    	void Append(const record& data) {
    		auto newNode = new Node(data);
    		Node *tmp;
    
    		for (tmp = head; tmp && tmp->Next(); tmp = tmp->Next());
    		head ? tmp->setNext(newNode) : head = newNode;
    	}
    
    	int Delete(const string& data, bool duplicate = false, bool all = false) {
    		bool first = true;
    		int cnt = 0;
    
    		for (Node* tmp = head, *prev = NULL; tmp;) {
    			if ((all == true) || ((tmp->getData().name == data) && (((duplicate == true) && (first == false)) || (duplicate == false)))) {
    					if (tmp != head)
    						prev->setNext(tmp->Next());
    					else {
    						head = tmp->Next();
    						prev = NULL;
    					}
    
    					delete tmp;
    					tmp = prev ? prev->Next() : head;
    					cnt++;
    			} else {
    				if ((first == true) && (tmp->getData().name == data))
    					first = false;
    
    				prev = tmp;
    				tmp = tmp->Next();
    			}
    		}
    		return cnt;
    	}
    
    	int Print() const {
    		int cnt = 0;
    		for (auto tmp = head; tmp; tmp = tmp->Next()) {
    			cout << tmp->getData().name << "-->";
    			cnt++;
    		}
    
    		cout << "NULL" << endl;
    		return cnt;
    	}
    
    	int Display() const {
    		int cnt = 0;
    		for (auto tmp = head; tmp; tmp = tmp->Next()) {
    			record rec = tmp->getData();
    			cout << left << setw(20) << rec.name << setw(3) << rec.gender << right << setw(4) << rec.age << endl;
    			cnt++;
    		}
    		return cnt;
    	}
    
    	int Export(ostream& os) const
    	{
    		int cnt = 0;
    
    		for (auto tmp = head; tmp; tmp = tmp->Next()) {
    			os << tmp->getData() << endl;
    			cnt++;
    		}
    
    		return cnt;
    	}
    
    	int Import(istream& is)
    	{
    		record rec;
    		int cnt = 0;
    
    		while (is >> rec) {
    			Append(rec);
    			cnt++;
    		}
    
    		return cnt;
    	}
    	
    	int Search(const string& value) const {
    		int cnt = 0;
    		for (auto tmp = head; tmp; tmp = tmp->Next())
    			if (tmp->getData().name == value)
    				cnt++;
    
    		return cnt;
    	}
    
    };
    
    int menu()
    {
    int choice = 0;
    
    	do {
    		cout << "\nMenu\n" << endl;
    		cout << "[1] Add an item." << endl;
    		cout << "[2] Remove item(s)." << endl;
    		cout << "[3] Search from the list." << endl;
    		cout << "[4] Display list links." << endl;
    		cout << "[5] Display list data." << endl;
    		cout << "[6] Inport from a file." << endl;
    		cout << "[7] Export to a file." << endl;
    		cout << "[8] remove all records." << endl;
    		cout << "[9] Quit.\n" << endl;
    		cout << "Your choice: ";
    
    		choice = 0;
    		if (!(cin >> choice) || (choice < 1) || (choice > max_choice)) {
    			cout << "Invalid choice. \nChoice needs to be in range 1 to " << max_choice << endl;
    			cin.clear();
    			cin.ignore(1000, '\n');
    		}
    	} while (choice < 1 || choice > max_choice);
    
    	return choice;
    }
    
    int main()
    {
    int choice = 0;
    LinkedList names;
    
    	do {
    		record data;
    		ifstream ifs;
    		ofstream ofs;
    		int fnd = 0;
    		string name;
    		char ans;
    
    		switch (choice = menu()) {
    			case 1:
    				cout << "Please enter a name to add (CASE sensitive): ";
    				cin.ignore(1000, '\n');
    				getline(cin, data.name);
    
    				while ((cout << "Insert gender (M/F): ") && (cin >> data.gender) && ((data.gender = (char)toupper(data.gender)) != 'M' && data.gender != 'F')) {
    					cout << "Please answer M for Male or F for Female\n";
    				}
    
    				cout << "Insert age: ";
    				cin >> data.age;
    
    				names.Append(data);
    				break;
    
    			case 2:
    				cout << "Please enter a name to remove (CASE sensitive): ";
    				cin.ignore(1000, '\n');
    				getline(cin, name);
    				while ((cout << "Remove duplicates (y/n): ") && (cin >> ans) && ((ans = (char)tolower(ans)) != 'y' && ans != 'n')) {
    					cout << "Please answer y or n\n";
    				}
    
    				(fnd = names.Delete(name, (ans == 'y'))) ? cout << " Deleted " << fnd << " occurances\n" : cout << " Not found\n";
    				break;
    
    			case 3:
    				cout << "Please enter a name to search (CASE sensitive): ";
    				cin.ignore(1000, '\n');
    				getline(cin, name);
    
    				(fnd = names.Search(name)) ? cout << "Found " << fnd << " occurances\n" : cout << "Not found\n";
    				break;
    
    			case 4:
    				cout << names.Print() << " records in list\n";
    				break;
    
    			case 5:
    				cout << names.Display() << " records displayed\n";
    				break;
    
    			case 6:
    				cout << "Enter name of import file: ";
    				cin.ignore(1000, '\n');
    				getline(cin, name);
    				ifs.open(name.c_str());
    				if (!ifs.is_open())
    					cout << "Cannot open input file\n";
    				else {
    					cout << names.Import(ifs) << " records imported\n";
    					ifs.close();
    				}
    				break;
    
    			case 7:
    				cout << "Enter name of export file: ";
    				cin.ignore(1000, '\n');
    				getline(cin, name);
    				ofs.open(name.c_str());
    				if (!ofs.is_open())
    					cout << "Cannot open output file\n";
    				else {
    					cout << names.Export(ofs) << " records exported\n";
    					ofs.close();
    				}
    				break;
    
    			case 8:
    				cout << names.Delete("", false, true) << " records deleted\n";
    				break;
    
    			case max_choice:
    				break;
    
    			default:
    				cout << "Something went wrong as we shouldn't get here!" << endl;
    
    		}
    	} while (choice != max_choice);
    
    	return 0;
    }
    Have fun! Hope you understand it and learn from it.
    Last edited by 2kaud; Feb 3rd, 2015 at 06:29 AM. Reason: option 7
    All advice is offered in good faith only. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Aug 2012
    Posts
    75

    Re: Pipe "|" delimited file into separate variables to insert into linked list

    Wow, 2kaud!
    This was fast! You've done everything for me!
    From the first look there are few new things for me in your code that I need to learn.
    I'll fiddle with this code a little bit and hope to understand how it works.

    Many-many thanks!

  4. #4
    Fanatic Member 2kaud's Avatar
    Join Date
    May 2014
    Location
    England
    Posts
    996

    Re: Pipe "|" delimited file into separate variables to insert into linked list

    Understanding other people's code (and criticising it!) is all part of the learning process. When I was first learning programming at Uni - way back when - I spent hours pouring over code trying to understand it.

    Have fun!
    All advice is offered in good faith only. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  5. #5
    Fanatic Member 2kaud's Avatar
    Join Date
    May 2014
    Location
    England
    Posts
    996

    Re: Pipe "|" delimited file into separate variables to insert into linked list

    You might like to have a look at this revised code - it now stores the name as first & last and can insert on name sorted order and imports in sorted order. Have fun

    Code:
    #include <iostream>
    #include <iomanip>
    #include <fstream>
    #include <string>
    #include <sstream>
    #include <cctype>
    using namespace std;
    
    const char delim = '|';
    const int max_choice = 10;
    
    struct record
    {
    	string first;
    	string last;
    	char gender;
    	int age;
    
    	record() : first(""), last(""), gender(' '), age(0) {}
    
    	bool operator==(const record& rec) const
    	{
    		return (rec.age == age && rec.gender == gender && rec.first == first && rec.last == last);
    	}
    
    	bool operator!=(const record& rec) const
    	{
    		return !operator==(rec);
    	}
    
    	void display() const
    	{
    		cout << left << setw(15) << first << " " << setw(15) << last << setw(3) << gender << right << setw(4) << age << endl;
    	}
    
    	int comp(const record& rec) const
    	{
    		if (last > rec.last)
    			return 1;
    
    		if (last < rec.last)
    			return -1;
    
    		if (first == rec.first)
    			return 0;
    		else
    			return (first > rec.first) ? 1 : -1;
    	}
    };
    
    string trim(const string& st)
    {
    size_t f = st.find_first_not_of(' ');
    size_t l = st.find_last_not_of(' ');
    
    	return (f != string::npos && l != string::npos) ? st.substr(f, l - f + 1) : "";
    }
    
    void split(const string& st, string& left, string& right)
    {
    string t = trim(st);
    size_t s = t.find_first_of(' ');
    
    	if (s != string::npos) {
    		left = trim(t.substr(0, s));
    		right = trim(t.substr(s + 1));
    	} else {
    		left = "";
    		right = t;
    	}
    }
    
    istream& operator>> (istream& is, record& rec)
    {
    string st;
    record tmp;
    
    	rec.age = 0;
    	rec.first = "";
    	rec.last = "";
    	rec.gender = ' ';
    
    	if (getline(is, st)) {
    		stringstream ss;
    		string dt;
    
    		ss.str(st);
    		getline(ss, dt, delim);
    		split(dt, tmp.first, tmp.last);
    		getline(ss, dt, delim);
    		tmp.gender = (char)toupper(trim(dt)[0]);
    		getline(ss, dt);
    		tmp.age = atoi(dt.c_str());
    
    		if (!is.fail())
    			rec = tmp;
    	}
    
    	return is;
    }
    
    ostream& operator <<(ostream& os, const record& rec)
    {
    	os << rec.first << " " << rec.last << delim << rec.gender << delim << rec.age;
    	return os;
    }
    
    class Node {
    	record data;
    	Node *next;
    
    public:
    	Node(const record& aData, Node* aNext = NULL) : data(aData), next(aNext) {}
    
    	record getData() const
    	{
    		return data;
    	};
    
    	Node* Next() const
    	{
    		return next;
    	}
    
    	Node* setNext(Node *aNext)
    	{
    		next = aNext;
    		return next;
    	}
    };
    
    class LinkedList {
    	Node *head;
    
    public:
    	LinkedList() : head(NULL) {}
    
    	~LinkedList() {
    		Delete("", false, true);
    	}
    
    	void Append(const record& data)
    	{
    		auto newNode = new Node(data);
    		Node *tmp;
    
    		for (tmp = head; tmp && tmp->Next(); tmp = tmp->Next());
    		head ? tmp->setNext(newNode) : head = newNode;
    	}
    
    	void Insert(const record& data)
    	{
    		auto newNode = new Node(data);
    		Node *tmp, *prev = NULL;
    
    		for ( tmp = head; tmp; tmp = tmp->Next()) {
    			const record& rec = tmp->getData();
    
    			if (data.comp(rec) < 0) {
    				if (prev) {
    					newNode->setNext(prev->Next());
    					prev->setNext(newNode);
    				} else {
    					newNode->setNext(head);
    					head = newNode;
    				}
    				return;
    			}
    			prev = tmp;
    		}
    
    		if (prev)
    			prev->setNext(newNode);
    
    		if (head == NULL)
    			head = newNode;
    	}
    
    	int Delete(const string& data, bool duplicate = false, bool all = false) 
    	{
    		bool first = true;
    		int cnt = 0;
    		string f, l;
    
    		split(data, f, l);
    
    		for (Node* tmp = head, *prev = NULL; tmp;) {
    			const record &rec = tmp->getData();
    
    			if ((all == true) || (((rec.first == f) && (rec.last == l)) && (((duplicate == true) && (first == false)) || (duplicate == false)))) {
    					if (tmp != head)
    						prev->setNext(tmp->Next());
    					else {
    						head = tmp->Next();
    						prev = NULL;
    					}
    
    					delete tmp;
    					tmp = prev ? prev->Next() : head;
    					cnt++;
    			} else {
    				if ((first == true) && ((rec.first == f) && (rec.last == l)))
    					first = false;
    
    				prev = tmp;
    				tmp = tmp->Next();
    			}
    		}
    		return cnt;
    	}
    
    	int Print() const
    	{
    		int cnt = 0;
    
    		for (auto tmp = head; tmp; tmp = tmp->Next()) {
    			const record &rec = tmp->getData();
    			cout << rec.first << " " << rec.last << " --> ";
    			cnt++;
    		}
    
    		cout << "NULL" << endl;
    		return cnt;
    	}
    
    	int Display() const
    	{
    		int cnt = 0;
    
    		for (auto tmp = head; tmp; tmp = tmp->Next()) {
    			tmp->getData().display();
    			cnt++;
    		}
    		return cnt;
    	}
    
    	int Export(ostream& os) const
    	{
    		int cnt = 0;
    
    		for (auto tmp = head; tmp; tmp = tmp->Next()) {
    			os << tmp->getData() << endl;
    			cnt++;
    		}
    
    		return cnt;
    	}
    
    	int Import(istream& is)
    	{
    		record rec;
    		int cnt = 0;
    
    		while (is >> rec) {
    			Insert(rec);
    			cnt++;
    		}
    
    		return cnt;
    	}
    	
    	int Search(const string& value, record& fnd) const
    	{
    		int cnt = 0;
    		string f, l;
    
    		split(value, f, l);
    		for (auto tmp = head; tmp; tmp = tmp->Next()) {
    			const record &rec = tmp->getData();
    
    			if ((rec.first == f) && (rec.last == l)) {
    				fnd = rec;
    				cnt++;
    			}
    		}
    
    		return cnt;
    	}
    };
    
    int menu()
    {
    int choice = 0;
    
    	do {
    		cout << "\nMenu\n" << endl;
    		cout << "[1] Append an item." << endl;
    		cout << "[2] Insert an item." << endl;
    		cout << "[3] Remove item(s)." << endl;
    		cout << "[4] Search from the list." << endl;
    		cout << "[5] Display list links." << endl;
    		cout << "[6] Display list data." << endl;
    		cout << "[7] Inport from a file." << endl;
    		cout << "[8] Export to a file." << endl;
    		cout << "[9] Remove all items." << endl;
    		cout << "[10] Quit.\n" << endl;
    		cout << "Your choice: ";
    
    		choice = 0;
    		if (!(cin >> choice) || (choice < 1) || (choice > max_choice)) {
    			cout << "Invalid choice. \nChoice needs to be in range 1 to " << max_choice << endl;
    			cin.clear();
    			cin.ignore(1000, '\n');
    		}
    	} while (choice < 1 || choice > max_choice);
    
    	return choice;
    }
    
    int main()
    {
    int choice = 0;
    LinkedList names;
    
    	do {
    		record data;
    		ifstream ifs;
    		ofstream ofs;
    		int fnd = 0;
    		string name;
    		char ans;
    
    		switch (choice = menu()) {
    			case 1:
    			case 2:
    				cout << "Please enter a name to add (CASE sensitive): ";
    				cin.ignore(1000, '\n');
    				getline(cin, name);
    				split(name, data.first, data.last);
    
    				while ((cout << "Insert gender (M/F): ") && (cin >> data.gender) && ((data.gender = (char)toupper(data.gender)) != 'M' && data.gender != 'F')) {
    					cout << "Please answer M for Male or F for Female\n";
    				}
    
    				cout << "Insert age: ";
    				cin >> data.age;
    
    				(choice == 1) ? names.Append(data) : names.Insert(data);
    				break;
    
    			case 3:
    				cout << "Please enter a name to remove (CASE sensitive): ";
    				cin.ignore(1000, '\n');
    				getline(cin, name);
    				while ((cout << "Remove duplicates (y/n): ") && (cin >> ans) && ((ans = (char)tolower(ans)) != 'y' && ans != 'n')) {
    					cout << "Please answer y or n\n";
    				}
    
    				(fnd = names.Delete(name, (ans == 'y'))) ? cout << " Deleted " << fnd << " occurances\n" : cout << " Not found\n";
    				break;
    
    			case 4:
    				cout << "Please enter a name to search (CASE sensitive): ";
    				cin.ignore(1000, '\n');
    				getline(cin, name);
    
    				if ((fnd = names.Search(name, data)) > 0) {
    					data.display();
    					cout << fnd << " occurances" << endl;
    
    				} else
    					cout << "Not found" << endl;
    
    				break;
    
    			case 5:
    				cout << names.Print() << " records in list\n";
    				break;
    
    			case 6:
    				cout << names.Display() << " records displayed\n";
    				break;
    
    			case 7:
    				cout << "Enter name of import file: ";
    				cin.ignore(1000, '\n');
    				getline(cin, name);
    				ifs.open(name.c_str());
    				if (!ifs.is_open())
    					cout << "Cannot open input file\n";
    				else {
    					cout << names.Import(ifs) << " records imported\n";
    					ifs.close();
    				}
    				break;
    
    			case 8:
    				cout << "Enter name of export file: ";
    				cin.ignore(1000, '\n');
    				getline(cin, name);
    				ofs.open(name.c_str());
    				if (!ofs.is_open())
    					cout << "Cannot open output file\n";
    				else {
    					cout << names.Export(ofs) << " records exported\n";
    					ofs.close();
    				}
    				break;
    
    			case 9:
    				cout << names.Delete("", false, true) << " records deleted\n";
    				break;
    
    			case max_choice:
    				break;
    
    			default:
    				cout << "Something went wrong as we shouldn't get here!" << endl;
    
    		}
    	} while (choice != max_choice);
    
    	return 0;
    }
    All advice is offered in good faith only. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  6. #6
    Fanatic Member 2kaud's Avatar
    Join Date
    May 2014
    Location
    England
    Posts
    996

    Re: Pipe "|" delimited file into separate variables to insert into linked list

    A possible way to split this into separate compilation units could be as attached.

    linklist.cpp
    linklist.h
    util.cpp
    util.h
    database.cpp
    All advice is offered in good faith only. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  7. #7
    Fanatic Member 2kaud's Avatar
    Join Date
    May 2014
    Location
    England
    Posts
    996

    Re: Pipe "|" delimited file into separate variables to insert into linked list

    For anyone following this thread, some further points of possible interest:

    - the class LinkedList needs a copy constructor as it uses dynamic storage and the default copy constructor does a shallow copy whilst in this case a deep copy is required. As it stands if the default copy constructor is invoked (eg passing a variable of this type by value to a function) then memory corruption will almost certainly occur. If a correct copy constructor is not provided, then the default compiler generated copy constructor should be removed so that a compiler error is generated if a copy constructor is tried to be used. In the LinkedList class declaration in linklist.h
    Code:
    LinkedList(const LinkedList& lst) = delete;

    - the record struct should have the data members as private not public (or a class with private data members) with getter/setter functions to retrieve/change the data elements. The setters would provide data validation so that the record would always hold valid data. Currently, for example, the age could be specified as -10 or 200! Or if say a birth date is stored then this date would be validated in the setter.

    - Import data doesn't check that the data has already been imported - so the same data can be imported multi times with duplicate records then being stored! Import data could empty the list first before the data is imported or a check for each import record for duplicate before storing the data (if a check for each import record then this would catch duplicate data in the import file).

    - the same applies to append/insert an item. A check could be made first to see if the item to insert already exists (using the search function).

    - no method is currently implemented to amend existing data. If already stored data is to be changed, then the record has to be first deleted and then re-input. For a record that contains just a couple of data items this isn't too onerous but if a record contains many data items then becomes time-consuming and error prone. Note that if changes are made to those parts of the data used for sort ordering then the amended record will need to be removed from the list and re-inserted in the correct order.
    All advice is offered in good faith only. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  8. #8

    Thread Starter
    Lively Member
    Join Date
    Aug 2012
    Posts
    75

    Re: Pipe "|" delimited file into separate variables to insert into linked list

    Thank you for these instructions. Helped me a lot further with my studies.
    Hope that some day I can be as good as 2kaud and help beginners with their studies.

    I think I can mark this thread as resolved

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width