Print 2 for loops next to each other - c++

I was wondering how can I print 2 for loops next to each other?
These are loops:
for(vector<Student>::iterator it = studenti.begin(); it != studenti.end(); ++it)
cout << "| " << it->brojIndeksa << " " << it->ime << " " << it->prezime;
for(map<string,string>::iterator it = ocjene.begin(); it!= ocjene.end(); ++it)
cout << " " << it->first << " - " << it->second << endl;
the output I want:
| brojIndeksa ime prezime first - second
| brojIndeksa ime prezime first - second
| brojIndeksa ime prezime first - second
the output I have:
| brojIndeksa ime prezime| brojIndeksa ime prezime first - second
first - second
EDIT:
struct Predmet {
string naziv;
string odsjek;
istream& dodaj_predmet(istream &);
void sort_predmeti();
};
struct Student {
string brojIndeksa;
string ime;
string prezime;
map<std::string, string> ocjene;
istream& dodaj_studenta(istream &);
void sort_studenti();
};
map<std::string, string> ocjene contains 2 strings for input, 1st one needs to be naziv from Predmet structure.
NEW OUTPUT:
| 1808 John Doe EJ 10
| PIM 10
| 1809 Jessica Doe PIM 10

You could iterate using both iterators in the same loop:
auto studenti_it = studenti.begin();
auto ocjene_it = ocjene.begin();
for (; studenti_it != studenti.end() && ocjene_it != ocjene.end(); ++studenti_it, ++ocjene_it)
{
// Print using both iterators...
}
After your edit where we see that the map is a member of the Student structure, I'm guessing what you want is to iterate over first the studenti vector, and then inside it have a loop for the Student::ocjene map?
Then you would have something like
// First iterate over the vector
for (auto const& student : studenti)
{
std::cout << "| " << student.brojIndeksa << " " << student.ime << " " << student.prezime << '\n';
// Then inside iterate over the map
for (auto const& oj : student.ocjene)
{
std::cout << '\t' << oj.first << ' ' << oj.second << '\n';
}
}

Related

Finding the max lengths of strings to format a table output

I want to find the max length of specific attributes from a vector of Person objects.
Below is an example of a Person object:
Person::Person(string first_name, string last_name, int the_age){
first = first_name;
last = last_name;
age = the_age;
}
I have a vector that stores Person objects, and I must print all the people out in a table, like so:
First Name Last Name Age
---------- ------------ ----
John Cool-Johnson 15
Paul Bob 1000
2 people
I need to find the max length of each attribute of a Person in order to grow each column according to the maximum length of name or age. How can I do this?
So far, I have tried lambdas using this code:
unsigned int max_name = *max_element(generate(people.begin(),people.end(), [](Person a){return a.getFirstName()})).size();
But I am not sure if this even works at all.
I must use <iomanip>, but I have no clue how it works.
Is there a better way?
Your use of std::max_element() is wrong. It takes 2 iterators for input, which you are not providing to it. It would need to look more like this:
auto max_name = max_element(
people.begin(), people.end(),
[](const Person &a, const Person &b){
return a.getFirstName().size() < b.getFirstName().size();
}
)->getFirstName().size();
Online Demo
Alternatively:
vector<string> names;
names.reserve(people.size());
for(const Person &p : people) {
names.push_back(p.getFirstName());
}
auto max_name = max_element(
names.begin(), names.end(),
[](const string &a, const string &b){
return a.size() < b.size();
}
)->size();
Online Demo
However, since you will probably also want to do the same thing for the Last Name and Age columns, I would suggest simply looping though the people vector manually, keeping track of the max lengths as you go along, eg:
string::size_type max_fname = 10;
string::size_type max_lname = 9;
string::size_type max_age = 3;
for(const Person &p : people)
{
max_fname = max(max_fname, p.getFirstName().size());
max_lname = max(max_lname, p.getLastName().size());
max_age = max(max_age, to_string(p.getAge()).size());
}
Then you can output everything in a table, eg:
cout << left << setfill(' ');
cout << setw(max_fname) << "First Name" << " " << setw(max_lname) << "Last Name" << " " << setw(max_age) << "Age" << "\n";
cout << setfill('-');
cout << setw(max_fname) << "" << " " << setw(max_lname) << "" << " " << setw(max_age) << "" << "\n";
cout << setfill(' ');
for(const Person &p : people)
{
cout << setw(max_fname) << p.getFirstName() << " " << setw(max_lname) << p.getLastName() << " " << setw(max_age) << p.getAge() << "\n";
}
cout << people.size() << " people\n";
Online Demo

list::iterator invalid for moved-to list?

I have used a decent amount of C++, but not so much std::list ..
In my current project I need a std::list<..> data member, as well as keep track to a position in the list with a std::list<..>::iterator. The object must also be movable, but a default move constructor is not possible in my case. Here std::list does something that surprises me.
Consider
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
template<typename T>
void test() {
T l { 1, 2, 3, 4, 5 };
cout << "l = "; for(const auto& e: l) cout << e << " "; cout << endl;
auto pos = find(l.begin(), l.end(), 6);
if (pos == l.end()) cout << "l end\n";
cout << "---- moving l > lmv ----" << endl;
T lmv { std::move(l) };
cout << "l = "; for(const auto& e: l) cout << e << " "; cout << endl;
cout << "lmv = "; for(const auto& e: lmv) cout << e << " "; cout << endl;
if (pos == l.end()) cout << "l end\n";
if (pos == lmv.end()) cout << "lmv end\n";
}
int main() {
cout << "___vector___\n";
test<vector<int>>();
cout << "___list___\n";
test<list<int>>();
}
This outputs
___vector___
l = 1 2 3 4 5
l end
---- moving l > lmv ----
l =
lmv = 1 2 3 4 5
lmv end
___list___
l = 1 2 3 4 5
l end
---- moving l > lmv ----
l =
lmv = 1 2 3 4 5
l end
I.e. the iterator that pointed to the moved-from lists end, does not point to the moved-to lists end.
But it does for vector, which is what I would always expect, if iterators are essentially pointers. Why is list different? Memory location of elements should not change with move .. does lists move change list iterators? Why?
I am using "g++.exe (Rev1, Built by MSYS2 project) 10.2.0"
under MSYS2 on Windows 10
Iterators should be preserved when moving a container.
However end iterators of a container don't point to an element and are therefore allowed to be invalidated when moving a container.
If you change your code to work with begin rather than end then it works as you expect.
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
template<typename T>
void test() {
T l { 1, 2, 3, 4, 5 };
cout << "l = "; for(const auto& e: l) cout << e << " "; cout << endl;
auto pos = find(l.begin(), l.end(), 1);
if (pos == l.begin()) cout << "l begin\n";
cout << "---- moving l > lmv ----" << endl;
T lmv { std::move(l) };
cout << "l = "; for(const auto& e: l) cout << e << " "; cout << endl;
cout << "lmv = "; for(const auto& e: lmv) cout << e << " "; cout << endl;
if (pos == l.begin()) cout << "l begin\n";
if (pos == lmv.begin()) cout << "lmv begin\n";
}
int main() {
cout << "___vector___\n";
test<vector<int>>();
cout << "___list___\n";
test<list<int>>();
}
Note that comparing the iterators from two different containers is undefined behaviour so the final pos == l.begin() is undefined behaviour and visual studio's debug builds at least will throw assertions when running this code.
I imagine your original code works because the std::vector end iterator is usually just implemented as pointing to one after the last element. I would imagine the std::list end iterator holds a null pointer and a pointer to the list.
If you add such horrible lines at the end of your test function
(this is totally incorrect, the sanitizer will insult you!),
you can see that in the case of a vector the end() iterator
designates something which is past-the-end of the buffer containing
the stored elements, but in the case of a list the end iterator
designates some kind of marker which is stored inside the list
structure itself.
Then, after moving, the buffer of the vector is still the same
but it does not belong to l anymore, so the address past-the-end
of this buffer is equivalent to end() for lmv.
On the other hand, after moving the list, pos which designated
an address inside l still designated the same address (although
l is moved from) but does not designate the end() marker inside
lvm which didn't even exist when pos was initialised.
std::cout << "pos: " << (void *)(&*pos) << '\n';
std::cout << "l: " << (void *)(&l) << '\n';
std::cout << "l.begin(): " << (void *)(&*l.begin()) << '\n';
std::cout << "l.end(): " << (void *)(&*l.end()) << '\n';
std::cout << "lmv: " << (void *)(&lmv) << '\n';
std::cout << "lmv.begin(): " << (void *)(&*lmv.begin()) << '\n';
std::cout << "lmv.end(): " << (void *)(&*lmv.end()) << '\n';

Could not print map of map value in C++

I have tried below code snippets to print map of map values but I could not able to access second map values.
#include <iostream>
#include <iterator>
#include <map>
#include <string>
using namespace std;
int main()
{
map< string, std::map<std::string, int> > someStorage;
//First key values
someStorage["key1"]["This Is Layer one"] = 100;
someStorage["Key1"]["This Is Layer Two"] = 120;
//second key, values
someStorage["key2"]["This Is Layer one"] = 110;
someStorage["key2"]["This Is Layer Two"] = 110;
map< string, std::map<std::string, int> > ::iterator itr;
cout << "\nThe map is : \n";
for (itr = someStorage.begin(); itr != someStorage.end(); ++itr)
{
cout << '\t' << itr->first;
//<< '\t' << (itr->second).first << '\n' <==problematic part
//<< '\t' << (itr->second).second << '\n'; <==problematic part
}
cout << endl;
return 0;
}
How to print/access these values and how do I differentiate "This Is Layer
one" for "key1" and "key2". Because I can see that it is getting
overwritten if we assign key2 value, key1 has same. Why?
Also I am expecting below key value pairs
Key1 => {This Is Layer one, 100}
{This Is Layer Two, 120}
Key2 =>{This Is Layer one, 110}
{This Is Layer Two, 110}
.
In addition to the other answers here, you can use structured binding (since c++17) to simplify this:
for (auto const& [key, val] : someStorage) { // val = second map
for (auto const& [k, v] : val) { // k = first, v = second
cout << key << ' ' << k << ' ' << v << '\n';
}
}
You need a second, inner loop to traverse the nested std::map. Like this:
for (auto itr = someStorage.cbegin(); itr != someStorage.cend(); ++itr)
{
cout << itr->first << " => ";
for (auto innerItr = itr->second.cbegin(); innerItr != itr->second.cend(); ++innerItr)
{
cout << innerItr->first << " : " << innerItr->second << " ";
}
cout << "\n";
}
Note that for the desired output, you need to capitalize the keys such that they are "Key1" and "Key2" (this is currently a typo in your question). Note further that I changed to begin/end member functions to cbegin/cend, as the loop doesn't modify the container.
You'll need to iterate over your inner map as well, something like:
for (auto itr1 = someStorage.begin(); itr1 != someStorage.end(); ++itr1)
{
cout << '\t' << itr->first << ":\n";
for (auto itr2 = itr1->second.begin(); itr2 != itr1->second.end(); ++itr2)
{
cout << "\t\t" << itr2->first << '\n';
cout << "\t\t" << itr2->second << '\n';
}
}
Thank you for the output. My Gcc version did not support auto iterate
for (itr1 = someStorage.begin(); itr1 != someStorage.end(); ++itr1)
{
cout << '\t' << itr1->first << ":\n";
std::map<std::string, int> ::iterator itr2;
for (itr2 = itr1->second.begin(); itr2 != itr1->second.end(); ++itr2)
{
cout << "\t\t" << itr2->first << '\n';
cout << "\t\t" << itr2->second << '\n';
}
}

Display vector struct within vector struct

I'm a true beginner and this is really complicated for me. I've been looking for an answer but i have not been able to find it here or if i have seen it.. it seems to be complicated for me.
Here is what I'm trying to do:
I have this headers
#include <iostream>
#include <string>
#include <vector>
And i have this structs
struct stFecha {
int dia;
int mes;
int ano;
};
struct stPersona {
string cedula;
string nombre;
string apellido;
stFecha fechaNacimiento;
char estado;
};
struct stCuentaBancaria{
string numeroCuenta;
string nombreOficialBancario;
double totalDebito;
double totalCredito;
vector<stPersona> clientesCuenta;
char estado;
i declared these vectors that are the ones i will be working with
vector<stPersona> clientes;
vector<stCuentaBancaria> cuentas;
And this is the code i'm using to iterate through the structs and check if a person already exists in the record.
for( vector<stPersona>::iterator it = clientes.begin(); !existe && it != clientes.end(); ++it )
{
existe = cedula.compare( (*it).cedula ) == 0 ;
if ( existe )
{
cout << "NOMBRE :" << (*it).nombre << '\n'
<< "APELLIDO :" << (*it).apellido << '\n'
<< "CEDULA :" << (*it).cedula << '\n'
<< "FECHA DE NACIMIENTO DD/MM/AAAA:\n"
<< "DIA: " << (*it).fechaNacimiento.dia << '\n'
<< "MES: " << (*it).fechaNacimiento.mes << '\n'
<< "A\xA5O: " << (*it).fechaNacimiento.ano << '\n'
<< "ESTADO: "<< (*it).estado << '\n';
}
I can see that even though fechaNacimientois a struct i can accesso the data in this struct easily because it is not a vector.
In the other hand before i add a new account to the vector cuentas i need to check if the ID or cedula is registered into my customer's clientes data. so I'm using this following code to find if the record exists.
stCuentaBancaria cuenta;
cout << "CEDULA DEL CLIENTE: ";
cin >> cedula;
bool existe = false;
for ( vector<stPersona>::iterator it = clientes.begin(); !existe && it != clientes.end(); ++it )
{
existe = cedula.compare( (*it).cedula ) == 0;
if ( existe )
{
cuenta.clientesCuenta.push_back((*it));
}
From my perspective it is supposed to copy the record found in clientes which is type stPersonato clientesCuenta which is as well a struct stPersona within the struct stCuentas which stands for the banking accounts. so far i get no errors.
But here is where i dont see how to get things working for me...
I wish to consult the records and when it finds the desired record to display the data within the record but when i did, as before with the iterator of the customers clientes, this one doesnt work. It contains a vector inside it gives me an error
cout<<"\n\n2.CONSULTA POR CUENTA\n";
string cuenta;
cout << "INTRODUCIR CUENTA A CONSULTAR .:";
cin >> cuenta;
bool existe = false;
for( vector<stCuentaBancaria>::iterator it = cuentas.begin(); !existe && it != cuentas.end(); ++it )
{
existe = cuenta.compare( (*it).numeroCuenta ) == 0 ;
if ( existe )
{
cout << "NUMERO DE CUENTA :" << (*it).numeroCuenta << '\n'
<< "NOMBRE OFICIAL DE CUENTA :" << (*it).nombreOficialBancario << '\n'
<< "TOTAL DEBITO : " << (*it).totalDebito << '\n'
<< "TOTAL CREDITO: " << (*it).totalCredito << '\n'
<< "ESTADO: "<< (*it).estado << '\n'
<< "TUTORIALES DE CUENTA: " << (*it).clientesCuenta << '\n';
}
I tried using (*it).clientesCuentabut this is the vector struct stPersonaswithin the vector cuentas previously declarated.
I dont know how do i get access to display this data nor how to get access to modify it in the future if i find it.
Please help.
additional note: I'm accessing this data through functions
int manejoCuentas(vector<stCuentaBancaria> &cuentas,vector<stPersona> &clientes, int &opcionMenu)
And this is how i send the data from the main function
manejoCuentas(cuentas, clientes, opcion);
My english is not very good thanks for reading this and any help would be more than welcome
Defining following three overloading of the operator <<, we can simplify the code that outputs the members of your PODs.
Since stFecha, stPersona and stCuentaBancaria are all POD types and their members are all public, we do not need to define friend functions on them:
#include <ostream>
std::ostream& operator<<(std::ostream& o, const stFecha& fecha)
{
o << "DIA : " << fecha.dia << '\n';
o << "MES : " << fecha.mes << '\n';
o << "A\\xA5O: " << fecha.ano;
return o;
}
std::ostream& operator<<(std::ostream& o, const stPersona& persona)
{
o << "NOMBRE : " << persona.nombre << '\n';
o << "APELLIDO : " << persona.apellido << '\n';
o << "CEDULA : " << persona.cedula << '\n';
o << "FECHA DE NACIMIENTO DD/MM/AAAA:\n";
o << persona.fechaNacimiento << '\n';
o << "ESTADO : " << persona.estado;
return o;
}
std::ostream& operator<<(std::ostream& o, const stCuentaBancaria& bancaria)
{
o << "NUMERO DE CUENTA : " << bancaria.numeroCuenta << '\n';
o << "NOMBRE OFICIAL DE CUENTA : " << bancaria.nombreOficialBancario << '\n';
o << "TOTAL DEBITO : " <<bancaria.totalDebito << '\n';
o << "TOTAL CREDITO : " << bancaria.totalCredito << "\n\n";
o << "TUTORIALES DE CUENTA\n";
for(const auto& ceunta_i : bancaria.clientesCuenta){
o << ceunta_i << "\n\n";
}
o << "ESTADO: "<< bancaria.estado;
return o;
}
Then you can output the data of each element of std::vector<stCuentaBancaria> cuentas to std::cout or some other output stream with just a one liner as follows.
DEMO
std::cout << *it << std::endl;
Override the function to output a vector of stCuentaBancaria
ostream& operator<<(ostream& os, const vector &cuentas)
for(int i=0; i< cuentas.size(); i++){
os << "TUTORIALES DE CUENTA: " << i << ' ' << cuentas[i] << '\n';
}
return *os;
}

C++ Array using string thats read in

my program is reading in 2 text files, one is going into an array and one is priming read normally. The one that is being read into an array has an item code, price, quantity, and item name. When the item code matches with the code on the other text document I need to get the price associated with it and cant figure out how.
while (!purchasesFile.eof())
{
purchasesFile >> PurchaseItem >> purchaseQty;
cout << purchaseNum << " " << PurchaseItem << " " << setw(4) <<
purchaseQty << " # " << dollarSign << endl;
int n = 0;
if (inventoryRec[n].itemCode != PurchaseItem)
{
inventoryRec[n+1];
}
else
{
cout << inventoryRec[n].itemPrice << endl;
inventoryRec[n+1];
}
if (PurchaseItem == inventoryRec[itemCount].itemCode)
{
inventoryRec[itemCount].itemOnHand - purchaseQty;
purchaseAmount = inventoryRec[itemCount].itemPrice * purchaseQty;
cout << purchaseAmount << " " <<
inventoryRec[itemCount].itemOnHand;
purchaseCount++;
}
purchasesFile >> purchaseNum;
}
purchasesFile.close();
There are several statements in your code that do nothing:
inventoryRec[n+1];
inventoryRec[itemCount].itemOnHand - purchaseQty;
What you are looking for is probably something like the STL map
typedef struct inventory_item_t {
inventory_item_t(const std::string& item_code, double price, int quantity) :
item_code(item_code),
price(price),
quantity(quanity) { }
std::string item_code;
double price;
int quantity;
} inventory_item_t;
typedef std::map<std::string, inventory_item_t> inventory_items_t;
inventory_items_t inventory_items;
inventory_items.insert(make_pair("item1", inventory_item_t("item1", 1.0, 1)));
inventory_items.insert(make_pair("item2", inventory_item_t("item2", 1.1, 2)));
inventory_items.insert(make_pair("item3", inventory_item_t("item3", 1.2, 3)));
inventory_items_t::iterator inventory_item = inventory_items.find("item1");
if(inventory_item != inventory_items.end()) {
std::cout << "Inventory Item found - item_code: ["
<< inventory_item->first
<< "], price: ["
<< inventory_item->second.price
<< "]"
<< std::endl;
} else {
std::cout << "Inventory Item not found" << std::endl;
}