Read data from text file into linked list of type user defined and then perform specific operations on it

Pages: 12
Create a C++ based grocery application in which list of items along with their unique item ID, name, description and price per item will be displayed on screen for the user to add/delete items of his/choice in/from a cart (cart will be generated as a singular linked list). The application should behave as follow:

• System should load item ID, name, description and price per item from a text file in to a linked list (items) and then it should display all loaded details on screen.
• After that user should be provided with four options, i.e. 0,1,2,3 in an iterative manner.
• If user presses 1, the system should ask user to enter item ID and quantity and should add it into the cart.
• If user presses 2, the system should ask for item ID and then it should delete that item from the cart.
• If user presses 3, list of items with item ID, name, description and price per item should be displayed again.
• If user presses 0, the system should generate bill containing selected item, quantity, price per item and total amount to pay.

Note:
1. For this application you need to create a text file containing items detail (one item per line).
2. Both linked lists (items and cart) must be of type <item>.

I have tried to perform first task in main class But I don't know how to pass data from text file into Linked List of type user defined Plz guide me on the first task Then kindly tell me what logic will be used on remaining tasks?

Item Class
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

  #include<iostream>
using namespace std;
template<class T>
class Item{
	private:
		T id,name,description,price;
		
	public:
		Item()
		{
			id=0;
			name=0;
			description=0;
			price=0;
		}
	void setId(T itm);
	T getId();
	void setName(T nam);
	T getName();
	void setDescription(T descrip);
	T getDescription();	
	void setPrice(T pric);
	T getPrice();
};

template<class T>
void Item<T>::setId(T itm)
{
	id=itm;
}
template<class T>
void Item<T>::setName(T nam)
{
	name=nam;
}
template<class T>
void Item<T>::setDescription(T descrip)
{
	description=descrip;
}
template<class T>
void Item<T>::setPrice(T pric)
{
	price=pric;
}
template<class T>
T Item<T>::getId()
{
	return id;
}
template<class T>
T Item<T>::getName()
{
	return name;
}
template<class T>
T Item<T>::getDescription()
{
	return description;
}
template<class T>
T Item<T>::getPrice()
{
	return price;
}

Node Class
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
#include<iostream>
using namespace std;
template<class T>
class Node{
	private:
		T info;
		Node<T> *next;
	public:
		Node(T i=0,Node<T> *n=0)//or:info(i),next(n)
		{
			info=i;//the bracket will remain empty
			next=n;
		}
	void setInfo(T item);
	T getInfo();
	void setNext(Node<T> *n);
	Node<T> *getNext();	
};
template<class T>
void Node<T>::setInfo(T item)
{
	info=item;
}//setInfo
template<class T>
void Node<T>::setNext(Node<T> *n)
{
	next=n;
}//setNext
template<class T>
T Node<T>::getInfo()
{
	return info;
}//getInfo
template<class T>
Node<T>* Node<T>::getNext()
{
	return next;
}//getNext 

Linked List class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include "Node.h"
#include "Item.h"
using namespace std;
template<class T>
class LinkedList{
	private:
	 Node<T> *head;
	 Node<T> *tail;
	
	public:
		LinkedList()
		{
			head=0;
			tail=0;
		}
}
I have not included functions  which are used in main class but I have them  in my IDE

Main Class
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
#include <iostream>
#include<fstream>
#include<string>
#include"LinkedList.h"
//#include"Item.h"
using namespace std;

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
	LinkedList<Item> items;
	
	Item word;
	ifstream obj;
	obj.open("E:\\C++ NUML\\Assignment LinkedList\\txt1.txt");
	if(!obj)
	{
		cout<<"File not found"<<endl;
	}
	else
	{
		while(getline(obj,word))
		{
			items.addToHead(word);
			items.traversing();
			cout<<endl;
		}
		obj.close();
	}
	
	
	return 0;
	
}
Last edited on
You problem is that the class Item is also templated. Is this rquired? If not you should remove the template. If it needs to be you need to choose a type for Item, probaly std::string. But I think the latter doesn't make much sense.
Yes there is confusion that should I declare Item class template or string but I think it would be better to declare it template
Last edited on
No, you shouldn't declare Item as string nor as template. When you insist to use template for Item you need to provide a type for the template argument like so:

LinkedList<Item<std::string>> items;

Again: It would be much better and makes much more sense to declare Item non templated:

1
2
3
4
5
6
class Item{
	private:
		std::string id;
		std::string name;
		std::string description;
		double price;


In your original code setting all variables to 0 doesn't make sense when they are not numeric. And I guess that something like description isn't numeric. While id might be.

Line 13: word is not an Item but a std::string. When one of the member variables are not string you need to convert the string.
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
#include<iostream>
using namespace std;
class Item{
	private:
		int id;
		string name;
		string description;
		double price;
		
	public:
		Item()
		{
			id=0;
			name="";
			description="";
			price=0;
		}
	void setId(int itm);
	int getId();
	void setName(string nam);
	string getName();
	void setDescription(string descrip);
	string getDescription();	
	void setPrice(double pric);
	double getPrice();
};


void Item::setId(int itm)
{
	id=itm;
}

void Item::setName(string nam)
{
	name=nam;
}

void Item::setDescription(string descrip)
{
	description=descrip;
}

void Item::setPrice(double pric)
{
	price=pric;
}

int Item::getId()
{
	return id;
}

string Item::getName()
{
	return name;
}

string Item::getDescription()
{
	return description;
}

double Item::getPrice()
{
	return price;
}


Take a look at it Is it fine?
Kindly guide me on passing text from file into linked list
here is text file:
1 Bread BreakFast 50
2 Butter Used with bread 60
3 Milk Gives calcium 80

first is id second is name third is description and last one is price
Last edited on
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
#include <iostream>
#include <string>

class Item {
private:
	int id{};
	std::string name;
	std::string description;
	double price{};

public:
	Item() {}
	void setId(int itm);
	int getId() const;
	void setName(const std::string& nam);
	std::string getName() const;
	void setDescription(const std::string& descrip);
	std::string getDescription() const;
	void setPrice(double pric);
	double getPrice() const;
};

void Item::setId(int itm) { id = itm; }
void Item::setName(const std::string& nam) { name = nam; }
void Item::setDescription(const std::string& descrip) { description = descrip; }
void Item::setPrice(double pric) { price = pric; }
int Item::getId() const { return id; }
std::string Item::getName() const { return name; }
std::string Item::getDescription() const { return description; }
double Item::getPrice() const { return price; }


Reading a file with a format as given above is a little more complicated as usual due to deciding when the description ends and the price starts. Watch this space...

To read and display the file using std::list, then consider:

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
#include <iostream>
#include <string>
#include <fstream>
#include <list>

class Item {
private:
	int id{};
	std::string name;
	std::string description;
	double price{};

public:
	Item() {}
	void setId(int itm);
	int getId() const;
	void setName(const std::string& nam);
	std::string getName() const;
	void setDescription(const std::string& descrip);
	std::string getDescription() const;
	void setPrice(double pric);
	double getPrice() const;
};

void Item::setId(int itm) { id = itm; }
void Item::setName(const std::string& nam) { name = nam; }
void Item::setDescription(const std::string& descrip) { description = descrip; }
void Item::setPrice(double pric) { price = pric; }
int Item::getId() const { return id; }
std::string Item::getName() const { return name; }
std::string Item::getDescription() const { return description; }
double Item::getPrice() const { return price; }

std::istream& operator>>(std::istream& is, Item& i) {
	int id{};
	std::string name;
	std::string desc;
	double price{};
	std::string tmp;

	if (is >> id >> name) {
		while (!(is >> price)) {
			is.clear();
			is >> tmp;
			if (!desc.empty())
				desc += ' ';

			desc += tmp;
		}

		i.setId(id);
		i.setName(name);
		i.setDescription(desc);
		i.setPrice(price);
	}

	return is;
}

std::ostream& operator<<(std::ostream& os, const Item& i) {
	return os << i.getId() << "  " << i.getName() << "  " << i.getDescription() << "  " << i.getPrice();
}

int main()
{
	std::ifstream ifs("grocery.txt");

	if (!ifs)
		return (std::cout << "Cannot open input file\n"), 1;

	std::list<Item> items;

	for (Item itm; ifs >> itm; items.push_back(itm));

	for (const auto& i : items)
		std::cout << i << '\n';
}



1  Bread  BreakFast  50
2  Butter  Used with bread  60
3  Milk  Gives calcium  80

Last edited on
Why have you declared int id{} and price like this?
Why have you not declared constructor?
Why are you using const?
Why are you using &(address) with name and description?
What is line 34 doing?
What is purpose of string tmp?
What is line 41-48 doing?
Why are you declaring const Item& in line 60?
What is line 73 and 75 doing?
{} means value initialise to default value - which for int is 0.

There's no need to have code in the constructor as the member variables are all initialised when defined.

const as used means that the method doesn't change member variables and so these can be used if the class defined variable is defined as const.

Using const std::string& instead of std::string means pass by const ref so that a copy isn't performed which would have been done if passed by value.

L34 overwrites the operator>> to work with class Item so that L73 works.

tmp is what is used to read each part of the description so that it can be concatenated with desc to get the description when the description is multiple words.

L41-48 is reading a line. It first gets the if and name which is easy. The issue is description which can contain multiple words. It assumes that there is no description and tries to read the price as a number. If this doesn't succeed then it hasn't read a price. It then tries to read a word as part of the description. This is repeated until reading a price succeeds.

L60 - same as using const std::string - pass by const ref to avoid a copy

L73 reads the contents of the file into the list items

L75-76 iterates the list using a range-for loop and displays the contents using the overloaded operator<< for Item
Why do you have Node as a separate class? Why not simply a private struct of LinkedList? Possibly simply something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<class T>
class LinkedList {
private:
	struct Node {
		T info{};
		Node* next{};

		Node(const T& data = T{}) : info(data) {}
	};

	Node *head{};
	Node *tail{};

public:
	LinkedList() {}
};

But how will I add items from linked list items into another linked list cart with quantity of each item since you have not created object of each line?
The functions of a list are not dependant upon the type of data being stored/used. The only thing external to the list class that is needed is the def of the stored data if this isn't of integral type.

In this case you'd define something like:

 
LinkedList<Item> cart;


You then insert/delete/get elements from cart as you would any list. If you want to change the value(s) of an element then have a method such as .find() that returns a pointer to the stored data (or nullptr if not found etc) then the data for that element can be changed.
Last edited on
Main Class
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
#include <iostream>
#include<fstream>
#include<string>
#include"LinkedList.h"
#define max 4 // define the max string
using namespace std;
string strings[max]; // define max string    
void split (string str, char seperator);  
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
	LinkedList<*Item> items;
	string line; 
	//char seperator =','; // space 
	ifstream obj;
	obj.open("E:\\C++ NUML\\Assignment LinkedList\\txt1.txt");
	if(!obj)
	{
		cout<<"File not opened"<<endl;
	}
	else
	{
		while(getline(obj,line))
		{
			split(line,','); 
			Item *p1=new Item(strings[0],strings[1],strings[2],strings[3]);
			items.addToHead(p1);
		}
	}
    cout <<" The split string is: ";  
    for (int i = 0; i < max; i++)  
    {  
        cout << "\n i : " << i << " " << strings[i];  
    }  
    return 0; 
	
}
void split (string str, char seperator)  
{  
    int currIndex = 0, i = 0;  
    int startIndex = 0, endIndex = 0;  
    while (i <=str.length())  
    {  
        if (str[i] == seperator || i == str.length())  
        {  
            endIndex = i;  
            string subStr = "";  
            subStr.append(str, startIndex, endIndex - startIndex);  
            strings[currIndex] = subStr;  
            currIndex += 1;  
            startIndex = endIndex + 1;  
        }  
        i++;  
        }     
}  

Add To Head function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template<class T>
void LinkedList<T>::addToHead(T item)
{
	Node<T> *ptr=new Node<T>(item);
	//or ptr->setInfo(item);
	if(head==0 && tail==0)//list is empty
	{
		head=ptr;
		tail=ptr;
		//orhead==tail==ptr;
	}
	else//non-empty
	{
		ptr->setNext(head);
		head=ptr;
	}
	
}//addToHead 

Item Class
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
#include<iostream>
using namespace std;
class Item{
	private:
		int id;
		string name;
		string description;
		double price;
		
	public:
		Item(int itm=0,string nam="",string descrip="",double pric=0)
		{
			id=itm;
			name=nam;
			description=descrip;
			price=pric;
		}
	void setId(int itm);
	int getId();
	void setName(string nam);
	string getName();
	void setDescription(string descrip);
	string getDescription();	
	void setPrice(double pric);
	double getPrice();
	void display()
{
	cout<<"Item Id:"<<id<<"/t"<<"Name:"<<name<<"/t"<<"Description:"<<description<<"/t"<<"Price:"<<price<<endl;
}
};


void Item::setId(int itm)
{
	id=itm;
}

void Item::setName(string nam)
{
	name=nam;
}

void Item::setDescription(string descrip)
{
	description=descrip;
}

void Item::setPrice(double pric)
{
	price=pric;
}

int Item::getId()
{
	return id;
}

string Item::getName()
{
	return name;
}

string Item::getDescription()
{
	return description;
}

double Item::getPrice()
{
	return price;
}

Text File
Id,Name,Description,Price
1,Bread,BreakFast,50
2,Butter,Used with bread,60
3,Milk,Gives calcium,80

I have tried to make program by using this logic which is much easier to read file line by line by using split string function My linked list and Node class are both template But Compiler is giving following error Kindly guide me on this

12 14 E:\C++ NUML\main.cpp [Error] '*' cannot appear in a constant-expression

12 18 E:\C++ NUML\main.cpp [Error] template argument 1 is invalid

12 25 E:\C++ NUML\main.cpp [Error] invalid type in declaration before ';' token

26 65 E:\C++ NUML\main.cpp [Error] no matching function for call to 'Item::Item(std::string&, std::string&, std::string&, std::string&)'

27 10 E:\C++ NUML\main.cpp [Error] request for member 'addToHead' in 'items', which is of non-class type 'int'
Last edited on
In mainclass, L12 you reference *Item - but the compiler knows at this point nothing about Item.

If you doing this using multiple files, then Item needs to be split into .h and .cpp files and the Item.h header filed included in main the same as LinkedList.h
What do you mean by item needs to be split in .h and .cpp file?
And my main is reading only one text file which I have given above
 
LinkedList<*Item> items;


How does the compiler know anything about Item? Don't you something like:

1
2
3
4
5
#include <iostream>
#include <fstream>
#include <string>
#include "LinkedList.h"
#include "Item.h"    // NOTE TELL THE COMPILER ABOUT Item 


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
#include <iostream>
#include<fstream>
#include<string>
#include"LinkedList.h"
#include"Item.h"
#define max 8 // define the max string
using namespace std;
string strings[max]; // define max string    
void split (string str, char seperator);
int len(string str);  
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
	LinkedList<Item*> items;
	string line; 
	//char seperator =','; // space 
	ifstream obj;
	obj.open("E:\\C++ NUML\\Assignment LinkedList\\txt1.txt");
	if(!obj)
	{
		cout<<"File not opened"<<endl;
	}
	else
	{
		while(getline(obj,line))
		{
			split(line,','); 
			Item *p1=new Item(strings[0],strings[1],strings[2],strings[3]);
			items.addToHead(p1);
		}
	}
    //cout <<" The split string is: ";  
    for (int i = 0; i < max; i++)  
    {  
        cout << " " << strings[i] ;  
    }  
    return 0; 
	
}
int len(string str)  
{  
    int length = 0;  
    for (int i = 0; str[i] != '\0'; i++)  
    {  
        length++;  
          
    }  
    return length;     
}  
  
// create custom split() function  
void split (string str, char seperator)  
{  
    int currIndex = 0, i = 0;  
    int startIndex = 0, endIndex = 0;  
    while (i <= len(str))  
    {  
        if (str[i] == seperator || i == len(str))  
        {  
            endIndex = i;  
            string subStr = "";  
            subStr.append(str, startIndex, endIndex - startIndex);  
            strings[currIndex] = subStr;  
            currIndex += 1;  
            startIndex = endIndex + 1;  
        }  
        i++;  
        }     
}  

Ouput 3 Milk Gives calcium 80
My code is reading only last line don't know why Kindly guide me
Use the debugger to trace through the code to find out why - but I would suspect .addToHead()

Why is type of LinkedList Item* instead of Item?

My teacher told me to declare Linked List like this and one thing If I declare my display function data type string in Item class then items.traversing function works perfectly but then p1.display() displays only first line on output but If I declare my display function void then items.traversing gives error but p1.display works fine and If I declare my display function int it works on p1.display but in items.traversing it display full output but output starts with some random numbers like this

1 Bread BreakFast 50
47498242 Butter Used with bread 60
47498243 Milk Gives calcium 80
4749824

Traversing function
1
2
3
4
5
6
7
8
9
10
template<class T>
void LinkedList<T>::traversing()
{
	Node<T> *ptr=head;
	while(ptr!=0)
	{
		cout<<ptr->getInfo()->display()<<"";
		ptr=ptr->getNext();
	}
}//traversing 
Pages: 12