Calculating the user entry

Pages: 12
Hello, I have no idea how to do this but any general code to start with would be fine. So I have a class that looks like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  #include <iostream>
using namespace std;

class Property
{
	string propname; //The name will be like Apartment, Terrace , etc.
	string proptype; //The type will be like Residential and Commercial.
	
	public :
		void set_data(string name, string type)
		{
			name = propname;
			type = proptype;
		}
		
	Property(){}
	Property data[10];
};


The system should able to calculate the total number of each property under different types. The types would only be between Residential and Commercial while the name would be various.
I'm not really sure what you're after. But 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
#include <iostream>
#include <string>
#include <map>

class Property
{
	std::string propname; //The name will be like Apartment, Terrace , etc.
	std::string proptype; //The type will be like Residential and Commercial.

public:
	std::string get_type() const { return proptype; }

	Property() {}
	Property(const std::string& name, const std::string& type) : propname(name), proptype(type) {}
};

int main()
{
	const Property props[] {{"Apartment", "Residential"}, {"Terrace", "Residential"}, {"Block", "Commercial"}};

	std::map<std::string, unsigned> pcnt;

	for (const auto& p : props)
		++pcnt[p.get_type()];

	for (const auto& [type, cnt] : pcnt)
		std::cout << type << "  " << cnt << '\n';

	std::cout << '\n';
}


which displays:


Commercial  1
Residential  2

It's like the user will input data for example : {"Apartment", "Residential"} , that would consider 1 Residential for Apartment only. Next, data like {"Terrace", "Residential"}, and that would be 1 Residential for Terrace. . Then if user would input new data like {"Apartment", "Residential"}, that would be 2 Residentials for Apartment. Then if again, new data, {"Apartment", "Commercial"} that would be 1 Commercial for Apartment.

Sorry if my English is bad.
the idea is still similar. you have a lookup table of integers that you increment as you encounter things.
it can be 2-d.
so rows are apartment, terrace, etc and columns are residential, commercial, etc (these can both be enums to keep in integer space) and so
table[apartment][commercial]++; //add one to commercial apartment when you find it.
you can use a string table to go back from enum to text for your output, but you will mostly be working with named integers via enum here.

1
2
3
4
5
6
7
8
9
10
11
12
int main()
{	
	enum {apartment, terrace, max_type1};
	enum {commercial, residential, max_type2};
        string t1[] { {"apartment"},{"terrace}"}};
	string t2[] { {"commercial"},{"residential"}};
	int table[max_type1][max_type2]{}; //zero initialized
	
	table[apartment][residential]++; //got one, incremenet it. 
	cout <<  t1[apartment] << " " << t2[residential] << " " << table[apartment][residential];
}   


you need to code "line 8" where you talk to the user or a file or whatever to get your data.

you can loop at the end:
for(int i = 0; i < max_type1; i++) ... etc to print everything in a report, and can even skip zero values in the table, and so on.
Last edited on
Okay, for now I get the idea. What does max_type1 and max_type2 do?
What if I actually have like {"apartment", "Terrace", "rent","price"}. Like more than 2 data in it.
Last edited on
For proof of concept, 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
#include <map>
#include <string>
#include <iostream>
#include <utility>
#include <iomanip>

int main()
{
	using Prop = std::pair<std::string, std::string>;

	const std::string t1[] {"apartment", "terrace", "semi detached", "detached"};
	const std::string t2[] {"commercial", "residential"};

	std::map<Prop, unsigned> cnts;

	cnts[Prop("apartment", "commercial")] = 1;
	cnts[Prop("terrace", "residential")] = 2;
	cnts[Prop("semi detached", "residential")] = 3;
	cnts[Prop("detached", "commercial")] = 1;

	std::cout << std::setw(13) << " ";
	for (const auto& t22 : t2)
		std::cout << std::left << std::setw(13) << t22;

	std::cout << '\n';

	for (const auto& t11 : t1) {
		std::cout << std::setw(17) << t11;

		for (const auto& t22 : t2) {
			const auto fnd {cnts.find(Prop(t11, t22))};
			std::cout << std::setw(13) << (fnd != cnts.end() ? fnd->second : 0);
		}

		std::cout << '\n';
	}
}


which displays:


             commercial   residential
apartment        1            0
terrace          0            2
semi detached    0            3
detached         1            0

Last edited on
the maxes are just 'handy' to have.
you can see that I used them for the array sizes and suggested to use one for loop iteration to print it all out.
you can do cool stuff with enums like that.
consider...

enum{dog,cat,bird, ANIMALS, pine, fir, oak, TREES};
for(int i = ANIMALS+1, i < TREES; i++)
//do something to all the trees

so embedding extra values lets you get a subset (you would rarely have 2 things THIS distinct as it is a silly example but you could have similar things that have 2-3 sub-categories)
if you want it even more readable/clean you can add first/last tagged entries for each category, eg
for(int i = FIRST_TREE+1; i < LAST_TREE; i++)

MOST of the time just having the final extra tag is useful and additional ones are silly.

so..
{apartment, Terrace, rent,price, max_type1}. note that enums do not have quotes, they are integer constants, not strings. I don't know that rent and price go with apt and terrace, logically, but its your code.... group things as you see fit..

also note that while we are using different tools, the underlying idea is the same. A map or a 2d array... a lookup table is a lookup table.

tying enums and arrays is sort of C ish / older tricks. The fancy modern containers have eliminated the need to do this for the most part, as above. The containers also allow you to avoid making a lot of classes -- pair/tuple/vector etc can be sufficient frequently where you wanted to make a little class.
Last edited on
Maybe something like this:

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <map>
#include <string>
#include <iostream>
#include <utility>
#include <iomanip>
#include <algorithm>
#include <limits>
#include <cctype>

template<typename T = int>
auto getNum(const std::string& prm)
{
	const auto notsp {[&]() {while (std::isspace(static_cast<unsigned char>(std::cin.peek())) && std::cin.peek() != '\n') std::cin.ignore(); return std::cin.peek() != '\n'; }};
	T n {};

	while ((std::cout << prm) && (!(std::cin >> n) || notsp())) {
		std::cout << "Not a number\n";
		std::cin.clear();
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	}

	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	return n;
}

using Prop = std::pair<std::string, std::string>;

const std::string t1[] {"apartment", "terrace", "semi detached", "detached"};
const std::string t2[] {"commercial", "residential"};
const auto mx {std::max(std::size(t1), std::size(t2))};

Prop getProp() {
	unsigned nam {}, typ {};

	std::cout << "\n    " << std::left << std::setw(24) << "Property name" << "Property type\n";

	for (size_t t = 0; t < mx; ++t) {
		if (t < std::size(t1))
			std::cout << std::left << std::setw(4) << t + 1 << std::setw(20) << t1[t];
		else
			std::cout << std::setw(24) << " ";

		if (t < std::size(t2))
			std::cout << std::left << std::setw(4) << t + 1 << t2[t];

		std::cout << '\n';
	}

	std::cout << '\n';

	do {
		nam = getNum<unsigned>("Enter property name number (0 to exit): ");
	} while (nam > std::size(t1) && (std::cout << "Invalid name no\n"));

	if (nam) {
		do {
			typ = getNum<unsigned>("Enter property type number: ");

		} while ((typ < 1 || typ > std::size(t2)) && std::cout << "Invalid type no\n");

		return {t1[nam - 1], t2[typ - 1]};
	}

	return {Prop{}};
}

void showProps(const std::map<Prop, unsigned>& cnts)
{
	std::cout << '\n' << std::setw(13) << " ";

	for (const auto& t22 : t2)
		std::cout << std::left << std::setw(13) << t22;

	std::cout << '\n';

	for (const auto& t11 : t1) {
		std::cout << std::setw(17) << t11;

		for (const auto& t22 : t2) {
			const auto fnd {cnts.find(Prop(t11, t22))};

			std::cout << std::setw(13) << (fnd != cnts.end() ? fnd->second : 0);
		}

		std::cout << '\n';
	}
}

int main()
{
	std::map<Prop, unsigned> cnts;
	unsigned opt {};

	do {
		std::cout << "\nProperty menu\n"
			<< "1. Add property\n"
			<< "2. Display property summary\n"
			<< "0. Quit\n\n";

		switch (opt = getNum<unsigned>("Enter option: ")) {
			case 1: {
				Prop p;

				do {
					p = getProp();
					if (!p.first.empty())
						++cnts[p];

				} while (!p.first.empty());
			}
			break;

			case 2:
				showProps(cnts);
				break;

			case 0:
				break;

			default:
				std::cout << "Invalid option\n";
				break;
		}
	} while (opt);
}

Hello, I understand for a 2d data. However I don't quite get it for my data that is more than 1.
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
#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <iomanip>
#include <limits>

using namespace std;
class Property
{
	private:
		string type; // residential/commercial
		float price;
		string name; //apartment/terrace/etc
		string recordtype; //sale/rent
		string availability;


		
	public:
		void set_details(string proptype, float propprice,
						 string propname, string proprecordtype, 
						 string propavailability)
		{
			type = proptype;
			price = propprice;
			name = propname;
			recordtype = proprecordtype;
			availability = propavailability;
		}
};

int main()
{
   Property data[10];
   data[0].set_details("Residential", 100, "Terrace", "Sale", "Yes");
   data[1].set_details( "Residential", 100, "Apartment", "Rent" );
   data[2].set_details( "Residential", 900, "Bungalow", "Sale" );
   data[3].set_details( "Commercial", 500, "Factory", "Rent" );
   data[4].set_details( "Commercial", 1200, "Mall", "Sale" );

}


I have these pre-set data and another function of adding new data by user(it works). I'm not sure how to apply the codes shown into mine.
A revision of my previous code without using std::map:

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <string>
#include <iostream>
#include <utility>
#include <iomanip>
#include <algorithm>
#include <limits>
#include <cctype>

template<typename T = int>
auto getNum(const std::string& prm)
{
	const auto notsp {[&]() {while (std::isspace(static_cast<unsigned char>(std::cin.peek())) && std::cin.peek() != '\n') std::cin.ignore(); return std::cin.peek() != '\n'; }};
	T n {};

	while ((std::cout << prm) && (!(std::cin >> n) || notsp())) {
		std::cout << "Not a number\n";
		std::cin.clear();
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	}

	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	return n;
}

const std::string t1[] {"apartment", "terrace", "semi detached", "detached"};
const std::string t2[] {"commercial", "residential"};
const auto mx {std::max(std::size(t1), std::size(t2))};

using Prop = std::pair<unsigned, unsigned>;
using PropSum = unsigned [std::size(t1)][std::size(t2)];

Prop getProp() {
	unsigned nam {}, typ {};

	std::cout << "\n    " << std::left << std::setw(24) << "Property name" << "Property type\n";

	for (size_t t = 0; t < mx; ++t) {
		if (t < std::size(t1))
			std::cout << std::left << std::setw(4) << t + 1 << std::setw(20) << t1[t];
		else
			std::cout << std::setw(24) << " ";

		if (t < std::size(t2))
			std::cout << std::left << std::setw(4) << t + 1 << t2[t];

		std::cout << '\n';
	}

	std::cout << '\n';

	do {
		nam = getNum<unsigned>("Enter property name number (0 to exit): ");
	} while (nam > std::size(t1) && (std::cout << "Invalid name no\n"));

	if (nam) {
		do {
			typ = getNum<unsigned>("Enter property type number: ");

		} while ((typ < 1 || typ > std::size(t2)) && std::cout << "Invalid type no\n");

		return {nam, typ};
	}

	return {Prop{}};
}

void showProps(const PropSum cnts)
{
	std::cout << '\n' << std::setw(13) << " ";

	for (const auto& t22 : t2)
		std::cout << std::left << std::setw(13) << t22;

	std::cout << '\n';

	for (unsigned t11 = 0; t11 < std::size(t1); ++t11) {
		std::cout << std::setw(17) << t1[t11];

		for (unsigned t22 = 0; t22 < std::size(t2); ++t22)
			std::cout << std::setw(13) << cnts[t11][t22];

		std::cout << '\n';
	}
}

int main()
{
	PropSum cnts {};
	unsigned opt {};

	do {
		std::cout << "\nProperty menu\n"
			<< "1. Add property\n"
			<< "2. Display property summary\n"
			<< "0. Quit\n\n";

		switch (opt = getNum<unsigned>("Enter option: ")) {
			case 1:
			{
				Prop p;

				do {
					p = getProp();
					if (p.first)
						++cnts[p.first - 1][p.second - 1];

				} while (p.first);
			}
			break;

			case 2:
				showProps(cnts);
				break;

			case 0:
				break;

			default:
				std::cout << "Invalid option\n";
				break;
		}
	} while (opt);
}

@nomnomu. It would have been useful if you had posted your latest code first so that we had more of an idea of what was required!

I'll have a look at it and revise mine at some point....
Sorry, I thought I could apply it with the general idea. I will do that from now
OK. I've done a first refactor. This still needs some work but I haven't time at the moment. I'll look at it again when I can. Is this now somewhere near what you are after?

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#include <string>
#include <iostream>
#include <utility>
#include <iomanip>
#include <algorithm>
#include <limits>
#include <cctype>

const std::string tnam[] {"Apartment", "Terrace", "Bungalow", "Factory", "Mall"};
const std::string ttyp[] {"Commercial", "Residential"};
const auto mx {std::max(std::size(tnam), std::size(ttyp))};
const size_t MaxProp {10};

using PropSum = unsigned[std::size(tnam)][std::size(ttyp)];

class Property
{
private:
	size_t itype {};		// Index into ttype
	float price {};
	size_t iname {};		// Index into tnam
	std::string recordtype;	//sale/rent
	bool avail {};

public:
	Property() {}
	Property(const std::string& proptype, float propprice,
		const std::string& propname, const std::string& proprecordtype,
		bool av = false) {
		set_details(proptype, propprice, propname, proprecordtype, av);
	}

	bool set_details(const std::string& proptype, float propprice,
		const std::string& propname, const std::string& proprecordtype,
		bool av = false) {
		price = propprice;
		recordtype = proprecordtype;
		avail = av;

		if (const auto fd {std::find(std::begin(ttyp), std::end(ttyp), proptype)}; fd != std::end(ttyp))
			itype = fd - std::begin(ttyp) + 1;
		else
			itype = 0;

		if (const auto fd {std::find(std::begin(tnam), std::end(tnam), propname)}; fd != std::end(tnam))
			iname = fd - std::begin(tnam) + 1;
		else
			iname = 0;

		return iname != 0 && itype != 0;
	}

	size_t getiname() const { return iname; }
	size_t getitype() const { return itype; }

	friend void displayProps(const Property props[], size_t noProp);
};

template<typename T = int>
auto getNum(const std::string& prm)
{
	const auto notsp {[&]() {while (std::isspace(static_cast<unsigned char>(std::cin.peek())) && std::cin.peek() != '\n') std::cin.ignore(); return std::cin.peek() != '\n'; }};
	T n {};

	while ((std::cout << prm) && (!(std::cin >> n) || notsp())) {
		std::cout << "Not a number\n";
		std::cin.clear();
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	}

	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	return n;
}

Property getProp() {
	unsigned nam {}, typ {};

	std::cout << "\n    " << std::left << std::setw(24) << "Property name" << "Property type\n";

	for (size_t t = 0; t < mx; ++t) {
		if (t < std::size(tnam))
			std::cout << std::left << std::setw(4) << t + 1 << std::setw(20) << tnam[t];
		else
			std::cout << std::setw(24) << " ";

		if (t < std::size(ttyp))
			std::cout << std::left << std::setw(4) << t + 1 << ttyp[t];

		std::cout << '\n';
	}

	std::cout << '\n';

	do {
		nam = getNum<unsigned>("Enter property name number (0 to exit): ");
	} while (nam > std::size(tnam) && (std::cout << "Invalid name no\n"));

	if (nam) {
		do {
			typ = getNum<unsigned>("Enter property type number: ");

		} while ((typ < 1 || typ > std::size(ttyp)) && std::cout << "Invalid type no\n");

		const auto price {getNum<float>("Enter price: ")};

		std::string salrnt;

		std::cout << "For sale or rent: ";
		std::cin >> salrnt;

		const bool avail = getNum<unsigned>("Is available (1 - yes, 0 - no: ");

		return {ttyp[typ - 1], price, tnam[nam - 1], salrnt, avail};
	}

	return {Property {}};
}

void showProps(const PropSum cnts)
{
	std::cout << '\n' << std::setw(13) << " ";

	for (const auto& t22 : ttyp)
		std::cout << std::left << std::setw(13) << t22;

	std::cout << '\n';

	for (unsigned t11 = 0; t11 < std::size(tnam); ++t11) {
		std::cout << std::setw(17) << tnam[t11];

		for (unsigned t22 = 0; t22 < std::size(ttyp); ++t22)
			std::cout << std::setw(13) << cnts[t11][t22];

		std::cout << '\n';
	}
}

void displayProps(const Property props[], size_t noProp)
{
	for (size_t i = 0; i < noProp; ++i) {
		const auto& p {props[i]};

		if (p.itype)
			std::cout << std::left << std::setw(17) << ttyp[p.itype - 1] << std::setw(14) << tnam[p.iname - 1]
			<< std::setw(7) << std::right << p.price << "   "
			<< std::setw(7) << std::left << p.recordtype << std::boolalpha << p.avail << '\n';
	}
}

int main()
{
	unsigned opt {};
	Property data[MaxProp] {};

	data[0].set_details("Residential", 100, "Terrace", "Sale", 1);
	data[1].set_details("Residential", 100, "Apartment", "Rent");
	data[2].set_details("Residential", 900, "Bungalow", "Sale");
	data[3].set_details("Commercial", 500, "Factory", "Rent");
	data[4].set_details("Commercial", 1200, "Mall", "Sale");

	size_t noProp {5};

	do {
		std::cout << "\nProperty menu\n"
			<< "1. Add property\n"
			<< "2. Display property summary\n"
			<< "3. Display all properties\n"
			<< "0. Quit\n\n";

		switch (opt = getNum<unsigned>("Enter option: ")) {
			case 1:
			{
				Property p;

				do {
					p = getProp();
					if (p.getiname())
						data[noProp++] = p;

				} while (p.getiname() && noProp < MaxProp);
			}
			break;

			case 2:
			{
				PropSum cnts {};

				for (size_t p = 0; p < noProp; ++p)
					++cnts[data[p].getiname() - 1][data[p].getitype() - 1];

				showProps(cnts);
			}
			break;

			case 3:
				displayProps(data, noProp);
				break;

			case 0:
				break;

			default:
				std::cout << "Invalid option\n";
				break;
		}
	} while (opt);
}

2nd revision:

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#include <string>
#include <iostream>
#include <utility>
#include <iomanip>
#include <algorithm>
#include <limits>
#include <cctype>

const std::string tnam[] {"apartment", "terrace", "bungalow", "factory", "mall"};
const std::string ttyp[] {"commercial", "residential"};
const std::string totain[] {"sale", "rent"};
const auto mx {std::max({std::size(tnam), std::size(ttyp), std::size(totain)})};
const size_t MaxProp {10};

using PropSum = unsigned[std::size(tnam)][std::size(ttyp)];

std::string tolower(const std::string& txt)
{
	std::string low;

	low.reserve(txt.size());

	for (const auto& ch : txt)
		low += static_cast<char> (std::tolower(static_cast<unsigned char>(ch)));

	return low;
}

std::string tocap(const std::string& txt)
{
	auto lc {tolower(txt)};

	if (!lc.empty())
		lc[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(lc[0])));

	return lc;
}

class Property
{
private:
	size_t itype {};		// Index into ttype
	size_t iname {};		// Index into tnam
	size_t iobtain {};		// Index into totain
	float price {};
	bool avail {};

public:
	Property() {}
	Property(const std::string& proptype, float propprice, const std::string& propname,
			const std::string& proprecordtype, bool av = false) {
		set_details(proptype, propprice, propname, proprecordtype, av);
	}

	bool set_details(const std::string& proptype, float propprice, const std::string& propname,
			const std::string& propobtain, bool av = false) {
		price = propprice;
		avail = av;
		itype = iobtain = iname = 0;

		if (const auto fd {std::find(std::begin(ttyp), std::end(ttyp), tolower(proptype))}; fd != std::end(ttyp))
			itype = fd - std::begin(ttyp) + 1;

		if (const auto fd {std::find(std::begin(totain), std::end(totain), tolower(propobtain))}; fd != std::end(totain))
			iobtain = fd - std::begin(totain) + 1;

		if (const auto fd {std::find(std::begin(tnam), std::end(tnam), tolower(propname))}; fd != std::end(tnam))
			iname = fd - std::begin(tnam) + 1;
		else
			iname = itype = iobtain = 0;

		return iname != 0;
	}

	size_t getiname() const { return iname; }
	size_t getitype() const { return itype; }

	friend void displayProps(const Property props[], size_t noProp);
};

template<typename T = int>
auto getNum(const std::string& prm)
{
	const auto notsp {[&]() {while (std::isspace(static_cast<unsigned char>(std::cin.peek())) && std::cin.peek() != '\n') std::cin.ignore(); return std::cin.peek() != '\n'; }};
	T n {};

	while ((std::cout << prm) && (!(std::cin >> n) || notsp())) {
		std::cout << "Not a number\n";
		std::cin.clear();
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	}

	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	return n;
}

Property getProp() {
	size_t nam {}, typ {}, obt {};

	std::cout << "\n    " << std::left << std::setw(24) << "Property name" << std::setw(24) << "Property type" << "Obtain\n";

	for (size_t t = 0; t < mx; ++t) {
		if (t < std::size(tnam))
			std::cout << std::left << std::setw(4) << t + 1 << std::setw(20) << tocap(tnam[t]);
		else
			std::cout << std::setw(24) << " ";

		if (t < std::size(ttyp))
			std::cout << std::left << std::setw(4) << t + 1 << std::setw(20) << tocap(ttyp[t]);
		else
			std::cout << std::setw(24) << " ";

		if (t < std::size(totain))
			std::cout << std::left << std::setw(4) << t + 1 << tocap(totain[t]);

		std::cout << '\n';
	}

	std::cout << '\n';

	do {
		nam = getNum<unsigned>("Enter property name number (0 to exit): ");
	} while (nam > std::size(tnam) && (std::cout << "Invalid name no\n"));

	if (nam) {
		do {
			typ = getNum<unsigned>("Enter property type number: ");

		} while ((typ < 1 || typ > std::size(ttyp)) && std::cout << "Invalid type no\n");

		const auto price {getNum<float>("Enter price: ")};

		do {
			obt = getNum<unsigned>("Enter property obtainability number: ");

		} while ((obt < 1 || obt > std::size(totain)) && std::cout << "Invalid obtain no\n");

		const bool avail = getNum<unsigned>("Is available (1 - yes, 0 - no: ");

		return {ttyp[typ - 1], price, tnam[nam - 1], totain[obt -1], avail};
	}

	return {Property {}};
}

void showProps(const PropSum cnts)
{
	std::cout << '\n' << std::setw(13) << " ";

	for (const auto& t22 : ttyp)
		std::cout << std::left << std::setw(13) << tocap(t22);

	std::cout << '\n';

	for (unsigned t11 = 0; t11 < std::size(tnam); ++t11) {
		std::cout << std::setw(17) << tocap(tnam[t11]);

		for (unsigned t22 = 0; t22 < std::size(ttyp); ++t22)
			std::cout << std::setw(13) << cnts[t11][t22];

		std::cout << '\n';
	}
}

void displayProps(const Property props[], size_t noProp)
{
	std::cout << '\n' << std::left << std::setw(17) << "Property Name" << std::setw(16) << "Property Type"
		<< std::setw(7) << "Price" << std::setw(7) << "Obtain" << " Avail\n";
	std::cout << std::setw(53) << std::setfill('-') << "-" << std::setfill(' ') << '\n';

	for (size_t i = 0; i < noProp; ++i) {
		const auto& p {props[i]};

		if (p.itype)
			std::cout << std::left << std::setw(17) << tocap(tnam[p.iname - 1]) << std::setw(14) << tocap(ttyp[p.itype - 1])
			<< std::setw(7) << std::right << p.price << "   "
			<< std::setw(7) << std::left << tocap(totain[p.iobtain - 1]) << std::boolalpha << p.avail << '\n';
	}
}

int main()
{
	unsigned opt {};
	Property data[MaxProp] {};

	data[0].set_details("Residential", 100, "Terrace", "Sale", 1);
	data[1].set_details("Residential", 100, "Apartment", "Rent");
	data[2].set_details("Residential", 900, "Bungalow", "Sale");
	data[3].set_details("Commercial", 500, "Factory", "Rent");
	data[4].set_details("Commercial", 1200, "Mall", "Sale");

	for (size_t i = 0; i < 5; ++i)
		if (data[i].getiname() == 0) {
			std::cout << "Error adding details\n";
			return 1;
		}

	size_t noProp {5};

	do {
		std::cout << "\n   Property menu\n\n"
			<< "1. Add property\n"
			<< "2. Display property summary by name/type\n"
			<< "3. Display all properties\n"
			<< "0. Quit\n\n";

		switch (opt = getNum<unsigned>("Enter option: ")) {
			case 1:
			{
				Property p;

				do {
					p = getProp();
					if (p.getiname())
						data[noProp++] = p;

				} while (p.getiname() && noProp < MaxProp);
			}
			break;

			case 2:
			{
				PropSum cnts {};

				for (size_t p = 0; p < noProp; ++p)
					++cnts[data[p].getiname() - 1][data[p].getitype() - 1];

				showProps(cnts);
			}
			break;

			case 3:
				displayProps(data, noProp);
				break;

			case 0:
				break;

			default:
				std::cout << "Invalid option\n";
				break;
		}
	} while (opt);
}

Thank you. However I can't run it. Some of the error says : 'size' is not a member of 'std'
What compiler or IDE do you use?
std::size is pretty new (C++20 ?)
Dev C++
std::size is from C++17 and is part of a number of headers.
https://en.cppreference.com/w/cpp/iterator/size

Dev C++ can set the standard to C++17.
It compiled OK with VS2019. As Furry Guy says, std::size is defined in several headers. If you are compiling as C++17 and still have an issue with this, try adding #include <iterator>
Last edited on
Okay, I got it now when I changed it to C++17. It's close to what I needed for the result. Thank you so much :)
Pages: 12