I have a std::map that stores a string and a class and i want to make an ordered vector based on the value of a class attribute. However, when i iterate over the vector, nothing prints. My code so far is this and the compiler sees no errors:
void Championship::orderTeams(std::vector<std::pair<std::string, class Team> > vect, std::map<std::string, class Team>& map) {
for (auto const& entry : map)
{
if (vect.empty()) { //check if vector is empty and add the first pair
vect.push_back(std::make_pair(entry.first, entry.second));
continue;
}
for (auto pos = vect.begin(); pos != vect.end(); ++pos) {
if(entry.second.points > pos->second.points){
vect.insert(pos, std::make_pair(entry.first, entry.second));
}else if (pos==vect.end()){
//vect.insert(pos, std::make_pair(entry.first, entry.second)); //wanted to check if there's a differance between insert and push_back
vect.push_back(std::make_pair(entry.first, entry.second));
}
}
}
}
Class Team only contains 3 public int values( points, goalsTaken and goalsGiven), constructor and distructor.
The vector of pairs is called teamOrdered and i printed using:
for (const auto & team : teamOrdered){
std::cout<<team.first<<" "<<team.second.points<<" "<<team.second.goalsScored<<" "<<team.second.goalsTaken<<std::endl;
}
There's a few issues in your code. Firstly, the reason why you get no output at all, is because the vector is passed in by value; therefore, any changes to vect inside the function are lost. You want to pass it in by reference instead. You can also pass the map in by const reference, since you don't need to change the map.
On top of that, your sort method doesn't actually work. Consider the inner for-loop's condition, pos != vect.end(); however, you have an else if which is pos == vect.end(), which is simply impossible. Further, even after the element is added, you keep attempting to add it to vect, with a potentially invalid iterator (inserting into a vector may cause iterator invalidity).
Here's a working example of you code:
void Championship::orderTeams(std::vector<std::pair<std::string, Team>> &vect, const std::map<std::string, Team>& map) {
for (auto const& entry : map)
{
if (vect.empty()) { //check if vector is empty and add the first pair
vect.push_back(std::make_pair(entry.first, entry.second));
continue;
}
bool added = false;
for (auto pos = vect.begin(); pos != vect.end(); ++pos) {
if(entry.second.points > pos->second.points){
vect.insert(pos, std::make_pair(entry.first, entry.second));
added = true;
break;
}
}
if (!added){
vect.push_back(std::make_pair(entry.first, entry.second));
}
}
}
This can also be simplified, using std::sort from the algorithm header, and instead of taking in a vector, you can return one instead.
std::vector<std::pair<std::string, Team>> orderTeams2( const std::map<std::string, Team>& map) {
std::vector<std::pair<std::string, Team>> vect = { map.begin(), map.end() };
std::sort( vect.begin(), vect.end(), []( auto &left, auto &right ) {
return left.second.points > right.second.points;
});
return vect;
}
As pointed by other people, nothing prints for you because you passed vector by value. Pass it by reference or return the vector.
Also, you can sort using std::sort and a predicate. Here's a working solution:
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
class Team {
public:
int points;
int goalsTaken;
int goalsGiven;
};
void orderTeams(std::vector<std::pair<std::string, class Team> >& vect, std::map<std::string, class Team>& map) {
for(auto currentIterator = map.begin(); currentIterator != map.end(); ++currentIterator) {
vect.emplace_back(currentIterator->first, currentIterator->second);
}
std::sort(vect.begin(), vect.end(),
[](const std::pair<std::string, class Team>& item1, const std::pair<std::string, class Team>& item2) -> bool { return item1.second.points > item2.second.points; });
}
int main()
{
std::vector< std::pair<std::string, class Team>> teamOrdered;
std::map<std::string, class Team> map;
map.emplace(std::string("4"), Team{ 4, 4, 4 });
map.emplace(std::string("2"), Team{ 2, 2, 2});
map.emplace(std::string("1"), Team{ 1, 1, 1 });
map.emplace(std::string("3"), Team{ 3, 3, 3});
orderTeams(teamOrdered, map);
for(const auto& team : teamOrdered) {
std::cout << team.first << " " << team.second.points << " " << team.second.goalsGiven << " " << team.second.goalsTaken << std::endl;
}
}
Related
I have inserted some elements in a 2D vector and want to know whether a given element is present in the 2D vector anywhere. Is there any quick way to find the presence of the element ?
The vector is declared as : vector < vector< int > > v;
If you don't have more information about the 2D vector (like somehow sorted), then the best way would be iterating over each row of the 2D vector and using find method to check if it exist or not.
You do something like the following:
bool does_exist(const vector< vector<int> >& v, int item){
vector< vector<int> >::const_iterator row;
for (row = v.begin(); row != v.end(); row++) {
if(find(row->begin(), row->end(), item) != row->end() )
return true;
}
return false;
}
You can test it with the follwing code:
#include <iostream>
#include <vector>
using namespace std;
int main(){
int item = 12;
vector < vector <int> > v;
vector <int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
vector <int> v2;
v2.push_back(4);
v2.push_back(5);
v2.push_back(6);
v.push_back(v1);
v.push_back(v2);
if( does_exist(v, item))
cout << "Item " << item << " exist" << endl;
else
cout << "Item " << item << " does not exist" << endl;
}
Not as elegant as I had hoped for. Given a 2D vector of int's:
std::vector<std::vector<int>> foo = {
{{1, 2, 3}},
{{5, 6, 7}},
{{8, 9, 13, 15}}
};
you could do this to see if the 13 is present:
bool found =
find_if(foo.begin(), foo.end(),
[](const std::vector<int>& v) -> bool {
return find(v.begin(), v.end(), 13) != v.end();
}) != foo.end();
TL;DR
Use std::find().
In C++, please use the function from Standard Template Library (STL) if it has been provided.
Elaboration
Let's say you have an 2d vector
std::vector<std::vector<int> > matrix = {
{1,2,3},
{4,5,6},
{7,8,9}
};
And if you want to iterate over all the elements in the 2d vector above.
I recommend you to use 2d iterator:
bool element_exist(const vector< vector<int> >& input, int key){
// 2d vector iterator
vector< vector<int> >::iterator row_it; //iterate over each row(s)
vector<int>::iterator col_it; //iterate over column(s)
for (row_it = input.begin(); row_it != input.end(); row_it++) { // iterate each row(s)
for (col_it = row_it->begin(); row_it != row_it->end(); col_it++) {
if(find(row_it->begin(), row_it->end(), key) != row_it->end())
return true;
}
}
}
and you can use another boolean variable to get the return value of the function key_exist
bool_var = element_exist(matrix, key);
Whole program
#include <vector>
#include <iostream>
using namespace std;
bool element_exist(const vector< vector<int> >& input, int key){
// 2d vector iterator
vector< vector<int> >::const_iterator row_it; //iterate over each row(s)
vector<int>::const_iterator col_it; //iterate over column(s)
for (row_it = input.begin(); row_it != input.end(); row_it++) { // iterate each row(s)
for (col_it = row_it->begin(); row_it != row_it->end(); col_it++) {
if(find(row_it->begin(), row_it->end(), key) != row_it->end())
return true;
}
}
}
int main() {
// declaration
bool bool_var = false; // default false
std::vector<std::vector<int> > matrix = {{1,2,3}, {4,5,6},{7,8,9}};
bool_var = element_exist(matrix,1);
cout << "bool_var: " << bool_var << endl;
return 0;
}
Result
bool_var: 1
I've just started to code in C++, so i'm new to STL .
Here i'm trying to iterate over a graph stored as vector of vectors.
#include <iostream>
#include <vector>
#include <iostream>
using namespace std;
int reach(vector<vector<int> > &adj, int x, int y) {
vector<vector<int> >::iterator it;
vector<int>::iterator i;
for (it = adj.begin(); it != adj.end(); it++)
{
cout << (*it) << endl;
if ((*it) == x)
for (i = (*it).begin(); i != (*it).end(); i++)
{
cout << (*i) << endl;
if ((*i) == y)
return 1;
}
}
return 0;
}
int main()
{
}
I'm getting an error std::vector<int> is not derived from const gnu cxx. Can someone point me in the right direction ?
*it pointing to vector not int that is why you are getting error
following code may work for you
#include <vector>
#include <iostream>
using namespace std;
int reach(vector<vector<int> > &adj, int x, int y) {
vector<vector<int> >::iterator it;
vector<int>::iterator i;
for (it = adj.begin(); it != adj.end(); it++)
{
cout << (*(*it).begin()) << endl;
if (( (*(*it).begin())) == x)
for (i = (*it).begin(); i != (*it).end(); i++)
{
cout << (*i) << endl;
if ((*i) == y)
return 1;
}
}
return 0;
}
int main()
{
}
for accessing first element of the vector of the use
(*(*it).begin()) in place of (*it)
if you are studying graph then use array of vector. for more details please go through following url
C++ Depth First Search (DFS) Implementation
cout << (*it) << endl;
Here, you declared it as a:
vector<vector<int> >::iterator it;
Therefore, *it is a:
vector<int>
So you are attempting to use operator<< to send it to std::cout. This, obviously, will not work. This is equivalent to:
vector<int> v;
cout << v;
There is no operator<< overload that's defined for what cout is, and a vector<int>. As you know, in order to print the contents of a vector, you have to iterate over its individual values, and print its individual values.
So, whatever your intentions were, when you wrote:
cout << (*it) << endl;
you will need to do something else, keeping in mind that *it here is an entire vector<int>. Perhaps your intent is to iterate over the vector and print each int in the vector, but you're already doing it later.
Similarly:
if ((*it) == x)
This won't work either. As explained, *it is a vector<int>, which cannot be compared to a plain int.
It is not clear what your intentions are here. "Graph stored as a vector or vectors" is too vague.
The following code compiles with the option std=c++11. But x is missing in vector<vector<int>>. If adj had type vector<pair<int, vector<int>>> it would better match.
The following code compiles for vector<vector<int>> but it doesn't use x.
using std::vector;
using std::pair;
using std::cout;
using std::endl;
int reach(vector<vector<int> > &adj, int x, int y) {
vector<vector<int> >::iterator it;
vector<int>::iterator i;
for(it=adj.begin();it!=adj.end();it++)
{
// cout << (*it) << endl;
for (const auto& nexts: *it)
cout << nexts << ' ';
cout << endl;
for(i=(*it).begin();i!=(*it).end();i++)
{
cout << (*i) << endl;
if((*i)==y)
return 1;
}
}
return 0;
}
This code compiles with <vector<pair<int, vector<int>>> and uses x.
using std::vector;
using std::pair;
using std::cout;
using std::endl;
int reach(vector<pair<int, vector<int> > > &adj, int x, int y) {
vector<pair<int, vector<int> > >::iterator it;
vector<int>::iterator i;
for(it=adj.begin();it!=adj.end();it++)
{
cout << it->first << endl;
if (it->first == x)
for(i=it->second.begin();i!=it->second.end();i++)
{
cout << (*i) << endl;
if((*i)==y)
return 1;
}
}
return 0;
}
Wrap it up in an iterator.
This can be templated for reuse.
Here is a minimal working example for the std::vector<T> container:
#include <iostream>
#include <utility>
#include <vector>
/// Iterable vector of vectors
/// (This just provides `begin` and `end for `Vector2Iterable<T>::Iterator`).
template<typename T>
class VovIterable
{
public:
static const std::vector<T> EMPTY_VECTOR;
/// Actual iterator
class Iterator
{
typename std::vector<std::vector<T>>::const_iterator _a1;
typename std::vector<T>::const_iterator _a2;
typename std::vector<std::vector<T>>::const_iterator _end;
public:
/// \param a1 Outer iterator
/// \param a2 Inner iterator
/// \param end End of outer iterator
explicit Iterator(typename std::vector<std::vector<T>>::const_iterator a1, typename std::vector<T>::const_iterator a2, typename std::vector<std::vector<T>>::const_iterator end)
: _a1(a1)
, _a2(a2)
, _end(end)
{
Check();
}
bool operator!=(const Iterator &b) const
{
return _a1 != b._a1 || _a2 != b._a2;
}
Iterator &operator++()
{
++_a2; // Increment secondary
Check();
return *this;
}
const T &operator*() const
{
return *_a2;
}
private:
void Check()
{
while (true)
{
if (_a2 != _a1->end()) // Is secondary live?
{
break;
}
// Increment primary
_a1++;
if (_a1 == _end) // Is primary dead?
{
_a2 = EMPTY_VECTOR.end();
break;
}
_a2 = _a1->begin(); // Reset secondary
}
}
};
private:
std::vector<std::vector<T>> _source;
public:
explicit VovIterable(std::vector<std::vector<T>> source)
: _source(std::move(source))
{
}
/// Start of vector of vectors
[[nodiscard]] Iterator begin() const
{
if (this->_source.empty())
{
return end();
}
return Iterator(this->_source.cbegin(), this->_source.cbegin()->cbegin(), this->_source.cend());
}
/// End of vector of vectors
[[nodiscard]] Iterator end() const
{
return Iterator(this->_source.cend(), EMPTY_VECTOR.end(), this->_source.cend());
}
};
template<typename T>
const std::vector<T> VovIterable<T>::EMPTY_VECTOR = {0};
/// Sample usage
int main()
{
std::vector<std::vector<int>> myVov{{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};
for (int i: VovIterable(myVov))
{
std::cout << i << std::endl;
}
return 0;
}
I'm trying to erase the last element in the vector using iterator. But I'm getting segmentation fault when erasing the element.
Below is my code:
for (vector<AccDetails>::iterator itr = accDetails.begin(); itr != accDetails.end(); ++itr) {
if (username == itr->username) {
itr = accDetails.erase(itr);
}
}
Is there something wrong with my iteration?
This is a good place to apply the remove/erase idiom:
accDetails.erase(
std::remove_if(
accDetails.begin(), accDetails.end(),
[username](AccDetails const &a) { return username == a.username; }),
accDetails.end());
As a bonus, this is likely to be a little bit faster than what you were doing (or maybe quite a bit faster, if your vector is large). Erasing each item individually ends up as O(N2), but this will be O(N), which can be pretty significant when/if N gets large.
If you can't use C++11, the lambda won't work, so you'll need to encode that comparison separately:
class by_username {
std::string u;
public:
by_username(std::string const &u) : u(u) {}
bool operator()(AccDetails const &a) {
return u == a.username;
}
};
accDetails.erase(
std::remove_if(accDetails.begin(), accDetails.end(), by_username(username)),
accDetails.end());
Alternatively, you can overload operator== for your AccDetails class, and handle the comparison there. For example:
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <iterator>
class AccDetail {
std::string name;
int other_stuff;
public:
AccDetail(std::string const &a, int b) : name(a), other_stuff(b) {}
bool operator==(std::string const &b) {
return name == b;
}
friend std::ostream &operator<<(std::ostream &os, AccDetail const &a) {
return os << a.name << ", " << a.other_stuff;
}
};
int main(){
std::vector<AccDetail> ad = { {"Jerry", 1}, { "Joe", 2 }, { "Bill", 3 } };
std::cout << "Before Erase:\n";
std::copy(ad.begin(), ad.end(), std::ostream_iterator<AccDetail>(std::cout, "\n"));
ad.erase(
std::remove(ad.begin(), ad.end(), "Joe"),
ad.end());
std::cout << "\nAfter Erasing Joe:\n";
std::copy(ad.begin(), ad.end(), std::ostream_iterator<AccDetail>(std::cout, "\n"));
}
I learn a safe way to erase elements from my leader. Firstly, find all the elements. Secondly, erase them one by one.
queue< vector<AccDetails>::iterator > q;
for (vector<AccDetails>::iterator itr = accDetails.begin(); itr != accDetails.end(); ++itr) {
if (username == itr->username) {
//itr = accDetails.erase(itr);
q.push(itr);
}
}
while(!q.empty()){
vector<AccDetails>::iterator itr = q.front();
accDetails.erase(itr);
q.pop();
}
I want to do something like this. Is there a stl algorithm that does this easily?
for each(auto aValue in aVector)
{
aMap[aValue] = 1;
}
If you have a vector of pairs, where the first item in the pair will be the key for the map, and the second item will be the value associated with that key, you can just copy the data to the map with an insert iterator:
std::vector<std::pair<std::string, int> > values {
{"Jerry", 1},
{ "Jim", 2},
{ "Bill", 3} };
std::map<std::string, int> mapped_values;
std::copy(values.begin(), values.end(),
std::inserter(mapped_values, mapped_values.begin()));
or, you could initialize the map from the vector:
std::map<std::string, int> m2((values.begin()), values.end());
Maybe like this:
std::vector<T> v; // populate this
std::map<T, int> m;
for (auto const & x : v) { m[x] = 1; }
You might std::transform the std::vector into a std::map
std::vector<std::string> v{"I", "want", "to", "do", "something", "like", "this"};
std::map<std::string, int> m;
std::transform(v.begin(), v.end(), std::inserter(m, m.end()),
[](const std::string &s) { return std::make_pair(s, 1); });
This creates std::pairs from the vector's elements, which in turn are inserted into the map.
Or, as suggested by #BenFulton, zipping two vectors into a map
std::vector<std::string> k{"I", "want", "to", "do", "something", "like", "this"};
std::vector<int> v{1, 2, 3, 4, 5, 6, 7};
std::map<std::string, int> m;
auto zip = [](const std::string &s, int i) { return std::make_pair(s, i); };
std::transform(k.begin(), k.end(), v.begin(), std::inserter(m, m.end()), zip);
Assuming items in vector are related in order, maybe this example can help :
#include <map>
#include <vector>
#include <string>
#include <iostream>
std::map<std::string, std::string> convert_to_map(const std::vector<std::string>& vec)
{
std::map<std::string, std::string> mp;
std::pair<std::string, std::string> par;
for(unsigned int i=0; i<vec.size(); i++)
{
if(i == 0 || i%2 == 0)
{
par.first = vec.at(i);
par.second = std::string();
if(i == (vec.size()-1))
{
mp.insert(par);
}
}
else
{
par.second = vec.at(i);
mp.insert(par);
}
}
return mp;
}
int main(int argc, char** argv)
{
std::vector<std::string> vec;
vec.push_back("customer_id");
vec.push_back("1");
vec.push_back("shop_id");
vec.push_back("2");
vec.push_back("state_id");
vec.push_back("3");
vec.push_back("city_id");
// convert vector to map
std::map<std::string, std::string> mp = convert_to_map(vec);
// print content:
for (auto it = mp.cbegin(); it != mp.cend(); ++it)
std::cout << " [" << (*it).first << ':' << (*it).second << ']';
std::cout << std::endl;
return 0;
}
A very generic approach to this, since you didn't specify any types, can be done as follows:
template<class Iterator, class KeySelectorFunc,
class Value = std::decay_t<decltype(*std::declval<Iterator>())>,
class Key = std::decay_t<decltype(std::declval<KeySelectorFunc>()(std::declval<Value>()))>>
std::map<Key, Value> toMap(Iterator begin, Iterator end, KeySelectorFunc selector) {
std::map<Key, Value> map;
std::transform(begin, end, std::inserter(map, map.end()), [selector](const Value& value) mutable {
return std::make_pair(selector(value), value);
});
return map;
}
Usage:
struct TestStruct {
int id;
std::string s;
};
std::vector<TestStruct> testStruct = {
TestStruct{1, "Hello"},
TestStruct{2, "Hello"},
TestStruct{3, "Hello"}
};
std::map<int, TestStruct> map = toMap(testStruct.begin(), testStruct.end(),
[](const TestStruct& t) {
return t.id;
}
);
for (const auto& pair : map) {
std::cout << pair.first << ' ' << pair.second.id << ' ' << pair.second.s << '\n';
}
// yields:
// 1 1 Hello
// 2 2 Hello
// 3 3 Hello
The parameter selector function is used to select what to use for the key in the std::map.
Try this:
for (auto it = vector.begin(); it != vector.end(); it++) {
aMap[aLabel] = it;
//Change aLabel here if you need to
//Or you could aMap[it] = 1 depending on what you really want.
}
I assume this is what you are trying to do.
If you want to update the value of aLabel, you could change it in the loop. Also, I look back at the original question, and it was unclear what they wanted so I added another version.
Yet another way:
#include <map>
#include <vector>
#include <boost/iterator/transform_iterator.hpp>
int main() {
using T = double;
std::vector<T> v;
auto f = [](T value) { return std::make_pair(value, 1); };
std::map<T, int> m(boost::make_transform_iterator(v.begin(), f),
boost::make_transform_iterator(v.end(), f));
}
But I don't think it beats range-for loop here in terms of readability and execution speed.
For converting values of a array or a vector directly to map we can do like.
map<int, int> mp;
for (int i = 0; i < m; i++)
mp[a[i]]++;
where a[i] is that array we have with us.
I'm trying to solve a issue where I'm inserting chars in to a map of type <char, int>. If the char already exists in the map I will increase the int by 1. I have created my own comparator for prioritizing the elements within the map. The priority doesn't work in the way I hope it would work since in the end the output doesn't follow the order.
#include <iostream>
#include <string>
#include <map>
#include <iterator>
using namespace std;
struct classcomp {
bool operator()(const int& a, const int& b) const {
return a < b;
}
};
bool isPresent(map<char,int,classcomp> mymap, char c){
return (mymap.find('b') != mymap.end());
}
int main(){
string input="dadbadddddddcabca";
map<char,int,classcomp> mymap;
char temp;
for(string::iterator it = input.begin(); it!=input.end(); ++it){
temp = *it;
if(!isPresent(mymap, temp))
mymap.insert(pair<char,int>(*it,1));
else
mymap[temp]++;
}
for (auto& x: mymap) {
cout << x.first << ": " << x.second << '\n';
}
return 0;
}
Gives the following output:
a: 4
b: 2
c: 2
d: 8
std::map is designed to be sorted by key, and providing comparator for type of value does not change anything. imagine you have std::map<char,char>, how would you think you can provide comparator for value (if it would be possible)?
So solution would be to use container that allows to sort by multiple keys like boost::multi_index or just create another map - reversed:
#include <iostream>
#include <string>
#include <map>
#include <iterator>
using namespace std;
int main(){
string input="dadbadddddddcabca";
map<char,int> mymap;
for(string::iterator it = input.begin(); it!=input.end(); ++it){
mymap[*it]++;
}
map<int,char> reversemap;
for (auto& x: mymap) {
reversemap.insert( make_pair( x.second, x.first ) );
}
for (auto& x: reversemap ) {
cout << x.first << ": " << x.second << '\n';
}
return 0;
}
Notice that your pre-check for element existance is completely redundant, std::map operator[] creates new element and initializes it, if it does not exists.
You may notice that in output you are missing some values now (though they are sorted), if that is not what you need, change reversemap type from map to multimap, which allows key duplicates.
The comparator is used to sort the chars and not the ints.
It is sorting the keys and seems to work just fine - a b c d.
map sorts its entries by key, not value. The char keys get silently cast to int in your classcomp::operator()
Why
mymap.find('b') != mymap.end());
and not
mymap.find(c) != mymap.end());
Maybe this is what you wanted
int main() {
std::string input="dadbadddddddcabca";
typedef std::map< char, int > map_t;
map_t mymap;
char temp;
for ( std::string::const_iterator it = input.begin(), e = input.end(); it != e; ++it ) {
temp = *it;
mymap[ temp ] = mymap[ temp ] + 1; // Hopufuly operator[] inserts zero initialized value, if can't find a key
}
typedef std::pair< typename map_t::key_type, typename map_t::mapped_type > pair_t;
std::vector< pair_t > sortedByValue;
sortedByValue.assign( mymap.begin(), mymap.end() );
std::sort( sortedByValue.begin(), sortedByValue.end(), []( const pair_t & left, const pair_t & right ) {
return left.second < right.second;
// change to
// return left.second > right.second;
// for descend order
} );
for ( const auto & x: sortedByValue ) {
std::cout << x.first << ": " << x.second << std::endl;
}
}
LWS link