i have an STL map ;
i would like to get the first non NULL value in the map;
is there an efficient/quick way to do that?
#include <map>
#include <algorithm>
#include <iostream>
using namespace std;
bool IsNotNull(const pair<const int, int>& i)
{
return i.second != 0;
}
int main() {
map<int, int> m;
m[0] = 0;
m[1] = 1;
map<int, int>::const_iterator it = find_if(m.begin(), m.end(), IsNotNull);
cout << it->second << endl;
return 0;
}
Ideone demo
There's nothing quicker than just looping through and finding what you're looking for
for (map<X,Y>::const_iterator i = m.begin(); i != m.end(); ++i)
{
if (i->second != NULL)
{
// do something with first non-NULL value
break;
}
}
Related
I am trying to get difference between consecutive elements in a std::list. I attempted the following solution but as this thread says, I need to make a copy of iterator and increment it. Not sure what it mean since adding number to iterators also result in error. what am I missing here. I am using a previous version of C++ but not C++ 11
#include "stdafx.h"
#include <list>
#include <iostream>
using namespace std;
int main()
{
std::list<int> myList;
//for (int i = 10;i < 15;i++)
myList.push_back(12);
myList.push_back(15);
myList.push_back(18);
myList.push_back(19);
myList.push_back(25);
for (std::list<int>::const_iterator itr = myList.begin();itr != myList.end();++itr)
{
int x = *itr;
int y = *(itr + 1);
int diff = std::abs(x - y);
cout << diff << "\n";
}
return 0;
}
How about using adjacent_difference ?
std::adjacent_difference(myList.begin(), myList.end(), tempList );
See Here
If you're interested in implementation look how its implemented in Possible Implementation section in attached link. All you have to do is replace with list iterator and for output just display on screen, or store it.
Use increment operator to move iterator.
auto x = itr;
auto y = itr;
if(++y!=myList.end())
{
int diff = std::abs(*x - *y);
cout << diff << "\n";
}
You can copy the iterator and run two, but I think it's easier to get the first value outside of the loop and then use the loop to iterate through the second value, resetting the first value with the second before proceeding to the next.
Something like this:
#include <list>
#include <iostream>
int main()
{
std::list<int> myList;
myList.push_back(12);
myList.push_back(15);
myList.push_back(18);
myList.push_back(19);
myList.push_back(25);
std::list<int>::const_iterator itr = myList.begin();
if(itr != myList.end()) // is a first value
{
int last = *itr; // cache it
for (itr++; itr != myList.end(); itr++) // get next value
{
int current = *itr; //cache it
int diff = std::abs(last - current);
std::cout << diff << "\n";
last = current; // update last value
}
}
return 0;
}
You can use std::advance() to get to the next iterator
int x = *itr;
std::list<int>::const_iterator itr2 = itr;
std::advance(itr2,1);
if(itr2==myList.end())
break;
int y = *(itr2);
int diff = std::abs(x - y);
cout << diff << "\n";
EDIT: If c++ 11 available, see std::next
#include <list>
#include <iostream>
int main()
{
std::list<int> myList;
//for (int i = 10;i < 15;i++)
myList.push_back(12);
myList.push_back(15);
myList.push_back(18);
myList.push_back(19);
myList.push_back(25);
for (std::list<int>::const_iterator itr = myList.begin();
itr != std::prev(myList.end());
++itr)
{
std::list<int>::const_iterator nextIt = std::next(itr);
int diff = *itr - *nextIt;
std::cout << diff << "\n";
}
return 0;
}
Use std::next(itr) to get next iterator
and use std::prev(myList.end()) in for loop to get previous of last element in list.
Also you can change your for loop and use std::advance() to get next iterator without using std::next and std::prev
std::list<int>::const_iterator itr = myList.begin();
while (true)
{
int prevValue= *itr;
std::advance(itr, 1);
if (itr == myList.end())
{
break;
}
int diff = prevValue - *itr;
std::cout << diff << "\n";
}
Another way would be to simply keep track of the previous list element value, not the iterator, and to subtract that previous value from the element the iterator is currently pointing to; like so:
#include <list>
#include <cmath> // need cmath for std::abs
#include <iostream>
using namespace std;
int main()
{
std::list<int> myList;
//for (int i = 10;i < 15;i++)
myList.push_back(12);
myList.push_back(15);
myList.push_back(18);
myList.push_back(19);
myList.push_back(25);
int PreviousElement = 0;
bool Start = false;
for (std::list<int>::const_iterator itr = myList.begin(); itr != myList.end(); ++itr)
{
if (Start)
{
int diff = std::abs(*itr - PreviousElement);
cout << diff << "\n";
}
else
{
Start = true;
}
PreviousElement = *itr;
}
return 0;
}
I think you need two iterator to solve this question
Here's my code
#include "stdafx.h"
#include <list>
#include <iterator>
#include <iostream>
using namespace std;
int main()
{
std::list<int> myList;
//for (int i = 10;i < 15;i++)
myList.push_back(12);
myList.push_back(15);
myList.push_back(18);
myList.push_back(19);
myList.push_back(25);
int x = 0;
int y = 0;
std::list<int>::iterator itr;
std::list<int>::iterator it_next;
for (itr = myList.begin(), it_next = ++myList.begin();it_next != myList.end();itr++, it_next++)
{
x = *itr;
y = *it_next;
int diff = abs(x - y);
cout << diff << "\n";
}
system("PAUSE");
return 0;
}
I build it in VC++2005 but it should work fine in C++
Hope this will help you :)
A container stores pointers to integers. I would like to find integer=66 using normal variable.
When I am trying to do this by pointer it is ok.
Code:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main ()
{
int *a=new int(22);
int *b=new int(44);
int *c=new int(66);
int d = 66;
vector<int*> v1;
v1.push_back(a);
v1.push_back(b);
v1.push_back(c);
std::vector<int*>::iterator it;
// it = find (v1.begin(), v1.end(), c); // Ok.
it = find (v1.begin(), v1.end(), d);
if (it != v1.end())
{
std::cout << "Element found in myvector: " << **it << '\n';
}
else
{
std::cout << "Element not found in myvector\n";
}
return 0;
}
I was trying to use find_if() function.
You could use a lambda function like this:
std::find_if(
std::begin(pointer_vec), std::end(pointer_vec),
[](const int *p){return p != nullptr && *p == 66;});
In C++11 you can do this:
it = find_if (v1.begin(), v1.end(), [d](int* p){ return *p == d; });
I am trying to get an output of the number of all the identical strings in a vector as part of a much larger program. After a lot of research I have managed to put something together that works but it seems messy and I was wondering if there was a better way to do it.
#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <iostream>
using namespace std;
void setMap(string i);
void addMap(string i);
map<string, int> myMap;
int main()
{
vector<string> myVector;
string myArray[6]={"foo","foo","bar","roo","foo","bar"};
for (int i=0; i<6; i++)
{
myVector.push_back(myArray[i]);
}
for_each (myVector.begin(), myVector.end(), setMap);
for_each (myVector.begin(), myVector.end(), addMap);
for (map<string, int, less< string >>::const_iterator iter = myMap.begin();
iter != myMap.end(); ++iter )
cout <<iter->first<<'\t'<<iter->second<<endl;
return 0;
}
void setMap(string i)
{
myMap[i]=0;
}
void addMap(string i)
{
myMap[i]++;
}
This code works fine and gives me the output I was after but I'm not that keen on having to add 2 extra functions to make it work or having to make the map global. Any hints would be gratefully received.
Well the simplest way to not have the extra functions and not have the map as global would be to not use for_each.
for_each (myVector.begin(), myVector.end(), setMap);
for_each (myVector.begin(), myVector.end(), addMap);
becomes
map<string, int> myMap;
for (vector<string>::iterator i = myVector.begin(); i != myVector.end(); ++i)
myMap[*i]=0;
for (vector<string>::iterator i = myVector.begin(); i != myVector.end(); ++i)
++myMap[*i];
Once you done that you could also remove the first loop
map<string, int> myMap;
for (vector<string>::iterator i = myVector.begin(); i != myVector.end(); ++i)
++myMap[*i];
since the map values will be initialised to zero anyway.
What made you think you had to use for_each anyway?
Your setMap function is unnecessary.
Consider what this function does, should the map's key not be present.
void addMap(string i)
{
myMap[i]++;
}
The expression myMap[i] will add a new key to your map.
Since the value type is int, this new value will be int(), which is guaranteed to be 0.
What about this? Encapsulate the counting mechanism in a separate function for reusability.
// Iterator pair based interface
template <class Iterator>
std::map<typename Iterator::value_type,int>
count(Iterator begin, Iterator end) {
std::map<typename Iterator::value_type,int> counts;
for (Iterator i = begin; i != end; ++i)
counts[*i]++;
return counts;
}
// Sequence interface
template <class Sequence>
inline std::map<typename Sequence::value_type,int>
count(Sequence seq) {
return count(seq.begin(), seq.end());
}
Then simply use it like this:
// C++11
for (const auto & c : count(myVector))
cout << c->first << '\t' << c->second << endl;
// C++03
std::map<string,int> counts = count(myVector);
for (std::map<string,int>::const_iterator c = counts.begin(), e = counts.end(); c != e; ++c)
cout << c->first << '\t' << c->second << endl;
Simple demo
Under C++11, you can do this:
#include <string>
#include <unordered_map>
#include <iostream>
int main() {
std::string myArray[6] = {"foo","foo","bar","roo","foo","bar"};
std::unordered_map<std::string, size_t> m;
for (const auto& s : myArray)
++m[s];
for (const auto& p : m)
std::cout << p.first << "\t" << p.second << std::endl;
}
This prints:
foo 3
bar 2
roo 1
This works because m[s] will automatically insert s into m if not already there.
Using std::unordered_map (a hashtable) is likely to be cheaper than std::map (a balanced tree).
You can do something very similar under C++03, except the "for each" loops shown above would be replaced by the regular "for" loops.
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <map>
using namespace std;
int main (int argc, char * const argv[]) {
string myArray[]={"foo","foo","bar","roo","foo","bar"};
int arr_length = 6;
vector<string> myVector(myArray, myArray + arr_length);
//Print contents of vector:
copy(myVector.begin(),
myVector.end(),
ostream_iterator<string>(cout, " ")
);
cout << endl;
map<string, int> myMap;
vector<string>::iterator pos;
for (pos=myVector.begin(); pos<myVector.end(); ++pos)
{
myMap[*pos] += 1;
}
map<string, int>::iterator mapPos;
for (mapPos=myMap.begin(); mapPos != myMap.end(); ++mapPos) {
cout << "word: " << mapPos->first << "\t"
<< "count: " << mapPos->second << endl;
}
return 0;
}
--output:--
foo foo bar roo foo bar
word: bar count: 2
word: foo count: 3
word: roo count: 1
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
In the program below I've a typedef map. What I want to do is to implement a hash table. I'm trying to use unordered_map since I heard that is the efficient as it takes O(1) time. I use my typedef map everywhere in my main program (another program that I'm working on) so I don't want to change that. I want to implement hash table in one of the functions and I'm trying to figure out how to insert the contents of my map into the hash table and search for the key later. I've inserted a comment in two places where I'm having trouble. Please help.
#include <iostream>
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <unordered_map>
using namespace std;
typedef vector<int> v_t;
typedef set<int> s_t;
typedef map<s_t, v_t> m_t;
typedef m_t::iterator m_it;
typedef std::unordered_map<s_t, v_t> Mymap;
int main(){
m_t sample;
for (int i = 0; i < 100; i = i+2) {
v_t v;
for(int k = 100 ; k<=105 ; ++k)
v.push_back(k);
s_t k;
k.insert(i);
sample.insert(sample.end(), make_pair(k, v));
}
//---------Debug--------------------
for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
cout << "Key: ";
copy(it->first.begin(), it->first.end(), ostream_iterator<int>(cout, " "));
cout << " => Value: ";
copy (it->second.begin(),it->second.end(),ostream_iterator<double>(cout," "));
cout << endl;
}
//---------------------------------
Mymap c1;
for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
c1.insert(Mymap::value_type(it->first,it->second)); // how to do this ?
}
s_t s;
s.insert(72);
if(c1.find(s)!=c1.end()) // does this work ?
cout << "Success" << endl;
return 0;
}
I appreciate any help or comments.
After reading Jason's comments I understand why i cannot use a std::set as a key in unordered_map so I tried to use std::string as a key but the find function won't work. Could you please help me.
Mymap c1;
for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
v_t v1;
std::string key;
key.insert(key.begin(),it->first.begin(),it->first.end());
copy(it->second.begin(), it->second.end(),std::back_inserter(v1));
c1.insert(Mymap::value_type(std::make_pair(key,v1)));
}
string s = "72";
if((c1.find(s) != c1.end()) == true)
cout << "Success" << endl;
return 0;
The basic element you're missing to make this work is to define a hashing function for your std::set that you're using as the key. The STL already defines equality and lexicographical ordering for a std::set, so you can use it as the key-value in a std::map as-is without any problems. It does not define a hash function though, so that is something you're going to have to-do by overloading std::hash. This is fairly straight-forward, and can be done by defining the following function:
namespace std
{
template<>
struct hash<std::set<int> > : public std::unary_function<std::set<int>, size_t>
{
size_t operator()(const std::set<int>& my_set) const
{
//insert hash algorithm that returns integral type
}
};
}
The above functor object would return an integral type of size_t, and would take a std::set as the argument. You'll have to define it inside of namespace std so that std::unordered_map will recognize it. An "easy" algorithm could be simply summing the elements since you have a set of type int. There are more complex algorithms out there that would reduce the number of collisions such a simple algorithm would create at the expense of hashing time. Once you have this defined though, you shouldn't have any problems inserting your std::set key-values into an unordered_map, as well as creating new key-values and finding them in the hash table.
You can see an example of your source-code working at: http://ideone.com/DZ5jm
EDIT: Jason's code placed here for reference:
#include <iostream>
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <unordered_map>
using namespace std;
namespace std
{
template<>
struct hash<set<int> > : public unary_function<set<int>, size_t>
{
size_t operator()(const std::set<int>& my_set) const
{
set<int>::iterator iter = my_set.begin();
int total = 0;
for (; iter != my_set.end(); iter++)
{
total += *iter;
}
return total;
}
};
}
typedef vector<int> v_t;
typedef set<int> s_t;
typedef map<s_t, v_t> m_t;
typedef m_t::iterator m_it;
typedef std::unordered_map<s_t, v_t> Mymap;
int main(){
m_t sample;
for (int i = 0; i < 100; i = i+2) {
v_t v;
for(int k = 100 ; k<=105 ; ++k)
v.push_back(k);
s_t k;
k.insert(i);
sample.insert(sample.end(), make_pair(k, v));
}
//---------Debug--------------------
for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
cout << "Key: ";
copy(it->first.begin(), it->first.end(), ostream_iterator<int>(cout, " "));
cout << " => Value: ";
copy (it->second.begin(),it->second.end(),ostream_iterator<double>(cout," "));
cout << endl;
}
//---------------------------------
Mymap c1;
for( m_it it(sample.begin()) ; it!=sample.end(); ++it) {
c1.insert(Mymap::value_type(it->first,it->second)); // how to do this ?
}
s_t s;
s.insert(72);
if(c1.find(s)!=c1.end()) // does this work ?
cout << "Success" << endl;
return 0;
}