I want to write a program which reads names in a vector. After that it should read ages into another vector. (that's done)
The first element of the name-vector should be connected to the first element of the age-vector, so if I use any kind of sort() function on the name-vector the age-vector gets sorted as well.
Is there any way to realize this in an easy way?
class Name_pairs {
public:
//member functions
int read_names();
int read_ages();
int print();
private:
vector<double> age;
vector<string> name;
};
int Name_pairs::read_names() {
cout << "Please enter different names, you want to store in a vector:\n";
for (string names; cin >> names;) {
name.push_back(names);
}
cin.clear();
cout << "You entered following names:\n\t";
for (int i = 0; i < name.size(); i++) {
cout << name[i] << " \n\t";
}
return 0;
}
int Name_pairs::read_ages() {
cout << "\nPlease enter an age for every name in the vector.\n";
for (double ages; cin >> ages;) {
age.push_back(ages);
}
return 0;
}
I think you need a std::vector of a coupled type.
struct Name_pair {
double age;
string name;
};
Than you can use std::vector<Name_pair> and use a lambda
auto comparator = [](const Name_pair& first, const Name_pair& second){return first.age <second.age;};
to sort your vector with std::sort.
Name_pairs = std::vector<Name_pair>;
// fill vector
std::sort(Name_pairs.begin(), Name_pairs.end(), comparator);
Here is a working example.
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
struct Name_pair {
double age;
std::string name;
};
int main() {
std::vector<Name_pair> Name_pairs{{13, "Hallo"}, {32, "Welt"}, {1, "Georg"}};
auto comparator = [](const Name_pair& first, const Name_pair& second) { return first.age < second.age; };
std::sort(Name_pairs.begin(), Name_pairs.end(), comparator);
for (const auto np : Name_pairs) {
std::cout << np.name << "\n";
}
}
It prints
Georg
Hallo
Welt
If you want to implement a data-oriented design by using separate vectors instead of a single vector of classes, you could use a vector of indeces and sort it.
The following is just an example:
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
class Customers
{
std::vector<double> ages_;
std::vector<std::string> names_;
template <typename Comparator>
auto make_indeces(Comparator &&comp)
{
std::vector<size_t> indeces(names_.size());
std::iota(indeces.begin(), indeces.end(), 0);
std::sort(indeces.begin(), indeces.end(), comp);
return indeces;
}
template <typename Type>
void reorder_vector(std::vector<Type> &src, std::vector<size_t> const &indeces)
{
std::vector<Type> tmp;
tmp.reserve(src.size());
std::generate_n(
std::back_inserter(tmp), src.size(),
[&src, idx = indeces.cbegin()] () mutable {
return src[*(idx++)];
});
src = std::move(tmp);
}
public:
void add(std::string const &name, double age)
{
names_.push_back(name);
ages_.push_back(age);
}
void sort_by_names()
{
auto indeces = make_indeces([this] (size_t i, size_t j) {
return names_[i] < names_[j];
});
reorder_vector(names_, indeces);
reorder_vector(ages_, indeces);
}
void show_sorted_by_ages()
{
auto indeces = make_indeces([this] (size_t i, size_t j) {
return ages_[i] < ages_[j];
});
for (auto i : indeces)
std::cout << names_[i] << ' ' << ages_[i] << '\n';
}
void show()
{
for (size_t i = 0; i < names_.size(); ++i)
std::cout << names_[i] << ' ' << ages_[i] << '\n';
}
};
int main(void)
{
Customers c;
c.add("Adam", 23);
c.add("Eve", 21);
c.add("Snake", 66.6);
c.add("Apple", 3.14);
std::cout << "Sorted by ages (doesn't modify the internal order):\n";
c.show_sorted_by_ages();
std::cout << "\nInternal order:\n";
c.show();
c.sort_by_names();
std::cout << "\nInternal order after sorting by names:\n";
c.show();
}
Testable HERE.
Related
As an old c99 person, I was often stubled upon the curly brakets initialization. In the `initializer_list`, I have to use {r, i} for a complex number. On the other hand, I have to use (r, i) for `complex` in the istream field. Here, I cut a part of my class that is able to run and give examples under codeblock 20.03 with MinGW 8.1.0.
#ifndef __tMatrix_class__
#define __tMatrix_class__
#include <iostream>
#include <initializer_list>
#include <iomanip>
#include <complex>
#include <sstream>
template <typename T> class tMatrix
{
public:
T *ptr;
int col, row, size;
inline T* begin() const {return ptr;}
inline T* end() const {return this->ptr + this->size;}
inline T operator()(const int i, const int j) const { return ptr[i*col+j]; } // r-value
inline T&operator()(const int i, const int j) { return ptr[i*col+j]; } //l-value
inline tMatrix(): col{0}, row{0}, size{0}, ptr{0} {;}
tMatrix(const int i, const int j): col(j), row(i), size(i*j) {
ptr = new T [this->size] ; }
tMatrix(const std::initializer_list< std::initializer_list<T> > s):tMatrix<T>(s.size(), s.begin()->size())
{
int j = 0;
for (const auto& i : s) { std::copy (i.begin(), i.end(), ptr + j*col); ++j ; }
}
tMatrix(const tMatrix<T>&a) : tMatrix<T>(a.row, a.col)
{
std::copy(a.begin(), a.end(), this->ptr);
}
tMatrix<T>& operator=(tMatrix<T>&&a)
{
this->col = a.col;
this->row = a.row;
delete [] this->ptr;
this->ptr = a.ptr;
a.ptr = nullptr;
return *this;
}
tMatrix<T>& operator=(const tMatrix<T>&a)
{
if (col==a.cpl && row==a.row) std::copy(a.begin(), a.end(), this->ptr);
else { tMatrix<T>&&v(a); *this = std::move(v);}
return *this;
}
tMatrix<T>& operator=(const std::initializer_list<std::initializer_list<T> > a)
{
tMatrix<T> &&v = a;
*this = std::move(v);
return *this;
}
~tMatrix() {delete [] this->ptr;}
void operator<<(const char*s)
{
std::stringstream ss;
ss.str(s);
for (int i=0; i<this->size; i++){
if (ss.good()) ss >> this->ptr[i];
else return;
}
}
}; //end of class tMatrix
template <typename X> std::ostream& operator<<(std::ostream&p, const tMatrix<X>&a)
{
p << std::fixed;
for (int i=0; i<a.row; i++) {
for (int j=0; j <a.col; j++) p << std::setw(12) << a(i, j);
p << std::endl;
}
return p;
}
using CMPLX = std::complex<double>;
using iMatrix = tMatrix<int>;
using rMatrix = tMatrix<double>;
using cMatrix = tMatrix< CMPLX >;
#endif
int main()
{
cMatrix cx(2,2);
cx = { { {1,2},{3,4} }, { {5,6}, {7,8} } };
std::cout << cx << std::endl;
cx << "(1,2) (3,4)";
std::cout << cx << std::endl;
return 0;
}
The above code renders correct format of complex number, and prints
$ ./ttt_mtx_init_fin_tmp.exe
(1.000000,2.000000)(3.000000,4.000000)
(5.000000,6.000000)(7.000000,8.000000)
(1.000000,2.000000)(3.000000,4.000000)
(5.000000,6.000000)(7.000000,8.000000)
But if I use the `()` in the initializer_list and `{}` in the istream filed, the results are all wrong. If I chagned the relavant part of main() to :
cx = { { (1,2),(3,4) }, { (5,6), (7,8) } };
std::cout << cx << std::endl;
cx << "{1,2} {3,4}";
std::cout << cx << std::endl;
Which renders all wrong values (compared with above):
$ ./ttt_mtx_init_fin_tmp.exe
(2.000000,0.000000)(4.000000,0.000000)
(6.000000,0.000000)(8.000000,0.000000)
(2.000000,0.000000)(4.000000,0.000000)
(6.000000,0.000000)(8.000000,0.000000)
I found it is rather confusion. So, my questions: is there a way to make these two expressions a same form? Many thanks for any helps.
I do not know any way to make std::istream::operator>> use { and } for std::complex, but if you are fine with using a helper, then you can replace the () in the input with {} and forward the input to the original operator>>:
#include <iostream>
#include <complex>
#include <sstream>
#include <algorithm>
template <typename T>
struct complex_reader {
std::complex<T>& target;
};
template <typename T>
complex_reader<typename T::value_type> get_complex_reader(T& t){ return {t};}
template <typename T>
std::istream& operator>>(std::istream& in,complex_reader<T> cr){
std::string input;
std::getline(in,input,'}'); // read till `}`
std::replace(input.begin(),input.end(),'{','(');
input += ')';
std::stringstream ss{input};
ss >> cr.target; // call the original >>
return in;
}
int main()
{
std::stringstream ss{"{2,2}"};
std::complex<double> x;
ss >> get_complex_reader(x);
std::cout << x;
}
Output:
(2,2)
However, you would have to write a similar helper to get consistent output (you may not provide an operator<< for std::complex<T> directly). Also note that the above implementation is a little simplistic. It reads from the stream until it encounters a }. For invalid input this may result in undesired effects and more sophisticated input validation is required.
Note that the operator>> takes the complex_helper by value to allow passing temporaries. Thats fine, because the member is a (non-const) reference.
This is not an answer, but a reasoning of my choice. After a series of cross conversions with `largest_prime_is_463035818`, I figured out what is my best choice for now (many thanks to his time and patience). A bottom line is becoming clear to me that I will not alter the input format of istream that is too much changed for pratical purpose, since file input is the major method to fetch data for a large matrix.
Under this constrain, I try to make the appearance of initializer_list as friendly as possible. I did some experiments, and found that the complex_literals expression is acceptable by initializer_list. And it looks ok to me.
using namespace std::complex_literals;
int main()
{
cMatrix cx(3,2);
cx = { { 1+2.2j , 4j}, { 5.3+6.5j , 8.3j}, {8.3, 5.6+4j} };
std::cout << cx << std::endl;
cx << " (1,2) (3,4) (5,6) (7,8) (2.3, 3.4) (2,7.8) ";
std::cout << cx << std::endl;
return 0;
}
And it works.
$ ./a.exe
(1.000000,2.200000) (0.000000,4.000000)
(5.300000,6.500000) (0.000000,8.300000)
(8.300000,0.000000) (5.600000,4.000000)
(1.000000,2.000000) (3.000000,4.000000)
(5.000000,6.000000) (7.000000,8.000000)
(2.300000,3.400000) (2.000000,7.800000)
Thank you for your patience, and please let me know if there are better ways.
There are tons of answers for sorting a vector of struct in regards to a member variable. That is easy with std::sort and a predicate function, comparing the structs member. Really easy.
But I have a different question. Assume that I have the following struct:
struct Test {
int a{};
int b{};
int toSort{};
};
and a vector of that struct, like for example:
std::vector<Test> tv{ {1,1,9},{2,2,8},{3,3,7},{4,4,6},{5,5,5} };
I do not want to sort the vectors elements, but only the values in the member variable. So the expected output should be equal to:
std::vector<Test> tvSorted{ {1,1,5},{2,2,6},{3,3,7},{4,4,8},{5,5,9} };
I wanted to have the solution to be somehow a generic solution. Then I came up with a (sorry for that) preprocessor-macro-solution. Please see the following example code:
#include <iostream>
#include <vector>
#include <algorithm>
struct Test {
int a{};
int b{};
int toSort{};
};
#define SortSpecial(vec,Struct,Member) \
do { \
std::vector<decltype(Struct::Member)> vt{}; \
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [](const Struct& s) {return s.Member; }); \
std::sort(vt.begin(), vt.end()); \
std::for_each(vec.begin(), vec.end(), [&vt, i = 0U](Struct & s) mutable {s.Member = vt[i++]; }); \
} while (false)
int main()
{
// Define a vector of struct Test
std::vector<Test> tv{ {1,1,9},{2,2,8},{3,3,7},{4,4,6},{5,5,5} };
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
// Call sort macro
SortSpecial(tv, Test, toSort);
std::cout << "\n\nSorted\n";
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
}
Since macros shouldn't be used in C++, here my questions:
1. Is a solution with the algorithm library possible?
2. Or can this be achieved via templates?
To translate your current solution to a template solution is fairly straight forward.
template <typename T, typename ValueType>
void SpecialSort(std::vector<T>& vec, ValueType T::* mPtr) {
std::vector<ValueType> vt;
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [&](const T& s) {return s.*mPtr; });
std::sort(vt.begin(), vt.end());
std::for_each(vec.begin(), vec.end(), [&, i = 0U](T& s) mutable {s.*mPtr = vt[i++]; });
}
And we can call it by passing in the vector and a pointer-to-member.
SpecialSort(tv, &Test::toSort);
Somewhow like this (You just need to duplicate, rename and edit the "switchToShort" funtion for the rest of the variables if you want):
#include <iostream>
#include <vector>
struct Test {
int a{};
int b{};
int toSort{};
};
void switchToShort(Test &a, Test &b) {
if (a.toSort > b.toSort) {
int temp = a.toSort;
a.toSort = b.toSort;
b.toSort = temp;
}
}
//void switchToA(Test& a, Test& b) { ... }
//void switchToB(Test& a, Test& b) { ... }
inline void sortMemeberValues(std::vector<Test>& data, void (*funct)(Test&, Test&)) {
for (int i = 0; i < data.size(); i++) {
for (int j = i + 1; j < data.size(); j++) {
(*funct)(data[i], data[j]);
}
}
}
int main() {
std::vector<Test> tv { { 1, 1, 9 }, { 2, 2, 8 }, { 3,3 ,7 }, { 4, 4, 6 }, { 5, 5, 5} };
sortMemeberValues(tv, switchToShort);
//sortMemeberValues(tv, switchToA);
//sortMemeberValues(tv, switchToB);
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
}
With range-v3 (and soon ranges in C++20), you might simply do:
auto r = tv | ranges::view::transform(&Test::toSort);
std::sort(r.begin(), r.end());
Demo
how do i access map of int and vectors of string in the passed_vector function.
I just want to print them in that function.
#include <iostream>
#include <vector>
#include <map>
#include <string>
using namespace std;
typedef vector< map< int, vector<string> > > vmis;
typedef map< int, vector<string> > mis;
typedef vector<string> vstr;
void passing_vector(const vmis &meetings);
//return size of vector
template< typename A > size_t n_elements( const A& a )
{
return sizeof a / sizeof a[ 0 ];
}
int main()
{
vmis meeting_info;
mis meeting_members;
vstr sw_vec;
vstr sys_vec;
string sw_team[] = {"Ricky", "John", "David"};
string sys_team[] = {"Simmon", "Brad", "Schmidt", "Fizio"};
sw_vec.insert(sw_vec.begin(), sw_team, sw_team + n_elements(sw_team) );
sys_vec.insert(sys_vec.begin(), sys_team, sys_team + n_elements(sys_team) );
meeting_members.insert(make_pair(520, sw_vec));
meeting_members.insert(make_pair(440, sys_vec));
meeting_info.push_back(meeting_members);
passing_vector(meeting_info);
return 0;
}
void passing_vector(const vmis &meetings)
{
vmis::iterator itvmis = meetings.begin();
//how do i access map of int and vectors of string.
//I just want to print them.
}
I know how to print them in main function.
vmis::iterator itvims = meeting_info.begin();
for( int i = 0; i < meeting_info.size(); i++ )
{
mis::iterator itm = meeting_members.begin();
for(itm; itm != meeting_members.end(); itm++ )
{
cout << itm->first << " : ";
vstr::iterator it = itm->second.begin();
for(it; it != itm->second.end(); it++)
cout << *it << " ";
cout << endl;
}
}
desired output
440 : Simmon Brad Schmidt Fizio
520 : Ricky John David
if there is a better way of doing this suggestions are always welcome.
The easiest aproach is to use auto, also since your meetings is const, you need to use const_iterator:
void passing_vector(const vmis &meetings)
{
vmis::const_iterator itvims = meetings.begin();
//how do i access map of int and vectors of string.
//I just want to print them.
for (;itvims != meetings.end(); ++itvims)
{
const auto& map_item = *itvims;
for (const auto& map_it : map_item)
{
int map_key = map_it.first;
const auto& str_vec = map_it.second;
for (const auto& str : str_vec)
{
std::cout << map_key << " - " << str << "\n";
}
}
}
}
[edit]
c++98 version:
void passing_vector(const vmis &meetings)
{
vmis::const_iterator itvims = meetings.begin();
//how do i access map of int and vectors of string.
//I just want to print them.
for (;itvims != meetings.end(); ++itvims)
{
const mis& map_item = *itvims;
for (mis::const_iterator map_it = map_item.begin(); map_it != map_item.end(); ++map_it)
{
int map_key = map_it->first;
const vstr& str_vec = map_it->second;
for (vstr::const_iterator sitr = str_vec.begin(); sitr != str_vec.end(); ++sitr)
{
std::cout << map_key << " - " << *sitr << "\n";
}
}
}
}
I have a vector of type struct with some elements, and trying to count the number of occurrences of an element(value) in its corresponding column of the vector. I know how to count on a simple vector, e.g on vector of type string. But am stuck on vector<struct>. Any possible solution or suggestion?
Sample code:
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
struct my_struct
{
std::string first_name;
std::string last_name;
};
int main()
{
std::vector<my_struct> my_vector(5);
my_vector[0].first_name = "David";
my_vector[0].last_name = "Andriw";
my_vector[1].first_name = "Jhon";
my_vector[1].last_name = "Monta";
my_vector[2].first_name = "Jams";
my_vector[2].last_name = "Ruth";
my_vector[3].first_name = "David";
my_vector[3].last_name = "AAA";
my_vector[4].first_name = "Jhon";
my_vector[4].last_name = "BBB";
for(int i = 0; i < my_vector.size(); i++)
{
int my_count=count(my_vector.begin(), my_vector.end(),my_vector[i].first_name);
/*I need help to count the number of occerencess of each "First_name" in a vector
For example: First_Name:- David COUNT:- 2 ...and so on for each first_names*/
std::cout << "First_Name: " << my_vector[i].first_name << "\tCOUNT: " << my_count << std::endl;
}
return 0;
}
but, the same code for a vector of type string,std::vector<std::string> works properly. see below:
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> my_vector;
my_vector.push_back("David");
my_vector.push_back("Jhon");
my_vector.push_back("Jams");
my_vector.push_back("David");
my_vector.push_back("Jhon");
for(int i = 0; i < my_vector.size(); i++)
{
int my_count = count(my_vector.begin(), my_vector.end(),my_vector[i]); //this works good
std::cout << "First_Name: " << my_vector[i] << "\tCOUNT: " << my_count << std::endl;
}
return 0;
}
You have to use std::count_if with correct predicate:
int my_count = std::count_if(my_vector.begin(), my_vector.end(),
[&](const my_struct& s) {
return s.first_name == my_vector[i].first_name;
});
Demo
The functor to replace lambda in C++03:
struct CompareFirstName
{
explicit CompareFirstName(const std::string& s) : first_name(s) {}
bool operator () (const my_struct& person) const
{
return person.first_name == first_name;
}
std::string first_name;
};
and then
int my_count = std::count_if(my_vector.begin(), my_vector.end(),
CompareFirstName(my_vector[i].first_name));
Demo
The problem lies within the block:
check_sort(l.begin(), l.end(), "list");
time_insert(insert_list, data);
check_sort(s.begin(), s.end(), "set");
time_insert(insert_set, data);
check_sort(v.begin(), v.end(), "vector");
time_insert(insert_vector, data);
The error states that the variables are not declared in the scope, but shouldn't l,s,v be universal variables here? What am I doing wrong.
#include <cmath>
#include <iterator>
#include <iostream>
#include <iomanip>
#include <vector>
#include <ctime>
#include <list>
#include <set>
#include <algorithm>
#include <cstdlib>
using namespace std;
typedef void Inserter(vector<double>);
vector<double> gen_data(int num_elts);
void insert_list(vector<double> data);
void insert_set(vector<double> data);
void insert_vector(vector<double> data);
void time_insert( Inserter inserter, vector<double> data);
template <class Iter> bool is_sorted(Iter first, Iter last);
template <class Iter> void check_sort(Iter first, Iter last, string cont_kind);
int main() {
srand(time(0));// initialize random number generator
cout << "How many elements for container? ";
int num_elts = 0;
while (cin >> num_elts) {
if (num_elts <= 0)
cout << "Error, should be > 1";
else {
vector<double> data = gen_data(num_elts);
check_sort(l.begin(), l.end(), "list");
time_insert(insert_list, data);
check_sort(s.begin(), s.end(), "set");
time_insert(insert_set, data);
check_sort(v.begin(), v.end(), "vector");
time_insert(insert_vector, data);
}
cout << "\nHow many elements for next container? ";
}
return 0;
}
void time_insert( Inserter inserter, vector<double> data) {
clock_t t1 = clock();
if (t1 == clock_t(-1)) { //if clock() doesn’t work
cerr << "sorry, no clock\n";
exit(1);
}
inserter(data);
clock_t t2 = clock();
if (t2 == clock_t(-1)) {
cerr << "sorry, clock overflow\n";
exit(2);
}
cout << "Elapsed time: " << fixed << setprecision(2)
<< double(t2-t1)/CLOCKS_PER_SEC << " seconds\n";
}
class Larger_than {
double v;
public:
Larger_than(double vv) : v(vv){}
bool operator()(double x) const {return x>v;}
};
// Sorts and then inserts data into a list
void insert_list(vector<double> data)
{
list<double> l;
for(int i=0; i < data.size(); i++){
list<double>::iterator p = find_if(l.begin(),l.end(), Larger_than(data[i]));
l.insert(p, data[i]);
}
}
// Sorts and then inserts data into a list
void insert_set(vector<double> data)
{
set<double> s;
for(int i=0; i < data.size(); i++){
set<double>::iterator p = find_if(s.begin(),s.end(), Larger_than(data[i]
));
s.insert(p, data[i]);
}
}
// Sorts and then inserts data into a list
void insert_vector(vector<double> data)
{
vector<double> v;
for(int i=0; i < data.size(); i++){
vector<double>::iterator p = find_if(v.begin(),v.end(), Larger_than(data
[i]));
v.insert(p, data[i]);
}
}
// generate num_elts random numbers in the range [0.0, 1.0),
// which are returned in a vector
vector<double> gen_data (int num_elts)
{
vector<double> result;
for (int i = 0; i < num_elts; i++) {
double datum = 1.0*rand()/RAND_MAX;
result.push_back(datum);
}
return result;
}
// is container spanned by [from, last) sorted?
template <class Iter> bool is_sorted(Iter first, Iter last)
{
Iter next = first; // next element
for (next++; next != last; next++, first++) {
if (*first > *next)
return false;
}
return true;
}
// prints a msg describing container kind, as well as whether container
// spanned by [from, last) is sorted
template <class Iter> void check_sort(Iter first, Iter last, string cont_kind)
{
cout << "Check: " << cont_kind << " is ";
if (!is_sorted(first, last)) cout << "not ";
cout << "sorted\n";
}
How should main know about s, l and v at all? They're local variables of completely unrelated functions (the insert_xxx ones), there's no way main could know about them. If you want to make them globally accessible, just make them global variables, i.e., put their definition before main:
// ...
list<double> l;
set<double> s;
vector<double> v;
int main(){
// ....
}
// ...
It looks like l is defined in the 'insert_list' function and would not available in main. Only variables defined insider your function are available.
You don't appear to have declared the variables at all. Why do you think they should exist in main? There are no globals or locals with those names anywhere that I can see. Try declaring them before using them.