How to copy_if from map to vector? - c++

I'd like to copy values that match a predicate (equal ints) from a map<string,int> to a vector<int>.
This is what I tried:
#include <map>
#include <vector>
#include <algorithm>
int main()
{
std::vector< int > v;
std::map< std::string, int > m;
m[ "1" ] = 1;
m[ "2" ] = 2;
m[ "3" ] = 3;
m[ "4" ] = 4;
m[ "5" ] = 5;
std::copy_if( m.begin(), m.end(), v.begin(),
[] ( const std::pair< std::string,int > &it )
{
return ( 0 == ( it.second % 2 ) );
}
);
}
The error message from g++ 4.6.1 is :
error: cannot convert 'std::pair<const std::basic_string<char>, int>' to 'int' in assignment
Is there a way to adjust the example to do the above copy?

With boost::range it is as easy as:
boost::push_back(
v,
m | boost::adaptors::map_values
| boost::adaptors::filtered([](int val){ return 0 == (val % 2); }));

Problem
The copy fails because you're copying from a map::iterator which iterates over pair<string const,int> to a vector::iterator which iterates over int.
Solution
Replace copy_if with for_each and do a push_back on your vector.
Example
std::for_each( m.begin(), m.end(),
[&v] ( std::pair< std::string const,int > const&it ) {
if ( 0 == ( it.second % 2 ) ) {
v.push_back(it.second);
}
}
);

The compiler error is actually quite succinct:
error: cannot convert 'std::pair<const std::basic_string<char>, int>' to 'int' in assignment
And that's exactly what the problem is. The map you're copying from has iterators that dereference to a pair<KEY,VALUE>, and there's no way to implicitly transform a pair<KEY,VALUE> to just a VALUE.
Because of this, you can't use copy or copy_if to copy from a map to a vector; but the Standard Library does provide an algorithm you can use, creatively called transform. transform is very similar to copy in that it takes two source iterators and a destination iterator. The difference is transform also takes a unary function that does the actual transformation. Using a C++11 lambda, you can copy the entire contents of a map to a vector like this:
transform( m.begin(), m.end(), back_inserter(v), [] (const MyMap::value_type& vt)
{
return vt.second;
});
What if you don't want to copy the entire contents of the map, but only some elements meeting certian criteria? Simple, just use transform_if.
What's that, you say? There is no transform_if in the Standard Library? Well yeah, you do have a point there. Frustratingly, there is no transform_if in the Standard Library. However writing one is a simple enough task. Here's the code:
template<class InputIterator, class OutputIterator, class UnaryFunction, class Predicate>
OutputIterator transform_if(InputIterator first,
InputIterator last,
OutputIterator result,
UnaryFunction f,
Predicate pred)
{
for (; first != last; ++first)
{
if( pred(*first) )
*result++ = f(*first);
}
return result;
}
As you might expect, using transform_if is like taking copy_if and mashing it together with transform. Here's some psudo-code to demonstrate:
transform_if( m.begin(), m.end(), back_inserter(v),
[] (const MyMap::value_type& vt) // The UnaryFunction takes a pair<K,V> and returns a V
{
return vt.second;
}, [] (const MyMap::value_type& vt) // The predicate returns true if this item should be copied
{
return 0 == (vt.second%2);
} );

std::copy_if won't allow you to transfer from one type to another, only to filter what to copy.
You could use std::transform to get rid of the key and then use std::remove_if:
std::vector<int> v;
std::transform(m.begin(), m.end(), std::back_inserter(v),
[] ( const std::pair< std::string,int > &it )
{
return it.second;
});
v.erase(
std::remove_if(
v.begin(), v.end(), [](const int value){ return (value % 2) != 0; }),
v.end());
However, a plain for loop would be more efficient and a lot easier to read.

I cannot understand why the simple for loop solution is not the preferred approach, for this problem
for (std::map< std::string, int >::iterator it = m.begin(); it != m.end(); ++it )
{
if ((it->second % 2) == 0)
v.push_back(it->second);
}
Except that it makes the code more readable it performs better. I wrote a simple benchmark to see how a for loop performs compared to the other proposed solutions:
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
#include <sstream>
int main(int argc, char *argv[])
{
std::map< std::string, int > m;
std::vector<int> v;
// Fill the map with random values...
srand ( time(NULL) );
for (unsigned i=0; i<10000; ++i)
{
int r = rand();
std::stringstream out;
out << r;
std::string s = out.str();
m[s] = r;
}
/////////// FOR EACH ////////////////////
clock_t start1 = clock();
for (unsigned k=0; k<10000; k++)
{
v.clear();
std::for_each( m.begin(), m.end(),
[&v] ( const std::pair< std::string,int > &it ) {
if ( 0 == ( it.second % 2 ) ) {
v.push_back(it.second);
}
}
);
}
clock_t end1=clock();
std::cout << "Execution Time for_each : " << (end1-start1) << std::endl;
/////////// TRANSFORM ////////////////////
clock_t start2 = clock();
for (unsigned k=0; k<10000; k++)
{
v.clear();
std::transform(m.begin(), m.end(), std::back_inserter(v),
[] ( const std::pair< std::string,int > &it )
{
return it.second;
});
v.erase(
std::remove_if(
v.begin(), v.end(), [](const int value){ return (value % 2) != 0; }),
v.end());
}
clock_t end2 = clock();
std::cout << "Execution Time transform : " << (end2-start2) << std::endl;
/////////// SIMPLE FOR LOOP ////////////////////
clock_t start3 = clock();
for (unsigned k=0; k<10000; k++)
{
v.clear();
for (std::map< std::string, int >::iterator it = m.begin(); it != m.end(); ++it )
{
if ((it->second % 2) == 0)
v.push_back(it->second);
}
}
clock_t end3=clock();
std::cout << "Execution Time Simple For Loop : " << (end3-start3) << std::endl;
}
The results I got are the following:
Execution Time for_each : 7330000
Execution Time transform : 11090000
Execution Time Simple For Loop : 6530000

Presumably you just want to retrieve the associated values from the map, not the keys.
The SGI version of STL has select1st and select2nd iterators for this kind of task.
Personally, however, I don't think this should really be done with copy -- you're transforming the data, not copying it. As such, I'd advise using std::transform with a functor to return the second item in the pair.

Related

Check std::vector has duplicates

I want to check if a vector of integers has any duplicates or not, and have to return true if it does. So I try to do something like this:
vector<int> uGuess = {1,2,3,3,4,5}
vector<int> a = uGuess;
sort(a.begin(), a.end());
bool d = unique(a.begin(), a.end());
And this will not work since unqiue cannot be assigned as a bool value.
How should I proceed towards this?
If I were to write a for loop to perform the same action, how should I do that?
The algorithm you're looking for is std::adjacent_find.
// The container must be sorted!
const std::vector<int> sortedVector = {1,2,3,3,4,5};
const bool hasDuplicates = std::adjacent_find(sortedVector.begin(), sortedVector.end()) != sortedVector.end();
Unlike std::unique, std::adjacent_find doesn't modify the container.
As a bonus, std::adjacent_find returns an iterator to the first element in the duplicate "pair":
const auto duplicate = std::adjacent_find(sortedVector.begin(), sortedVector.end());
if (duplicate != sortedVector.end())
std::cout << "Duplicate element = " << *duplicate << "\n";
Looking at google for std::unique I found this page std::unique. I looked at what it did:
Eliminates all except the first element from every consecutive group of equivalent elements from the range [first, last)
So it looks like it does what you want - removes the duplicates.
I then looked at what it returns...
... returns a past-the-end iterator for the new logical end of the range
So the result from std::unique is a sequence which is not necessary the same as the whole vector.
If nothing was removed, the return value would be the end of the vector.
So you want:
vector<int>::iterator it = std::unique(a.begin(), a.end());
bool wasUnique = (it == a.end());
Or for C++11:
auto it = std::unique(a.begin(), a.end());
bool wasUnique = (it == a.end());
Finally for the unique function to work, the vector needs to be sorted, so the complete code would be:
sort(a.begin(), a.end());
auto it = std::unique(a.begin(), a.end());
bool wasUnique = (it == a.end());
You should using set
set<int> s(a.begin(), a.end());
return s.size() != a.size();
If someone is forced to write own algorithm:
bool hasDuplicates(const std::vector<int>& arr) {
for (std::size_t i = 0; i < arr.size(); ++i) {
for (std::size_t j = i + 1; j < arr.size(); ++j) {
if (arr[i] == arr[j])
return true;
}
}
return false;
}
But in real code you should use things that already exist, and in the standard library.
Sort the vector if it's not already sorted, and then use std::unique(), like this:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v = {3, 1, 3, 4, 5};
sort(v.begin(), v.end());
auto it = std::unique(v.begin(), v.end());
std::cout << ((it == v.end()) ? "Unique\n" : "Duplicate(s)\n");
return 0;
}
Output:
Duplicate(s)
So far all these solutions either modify the container or have O(n²) complexity. You can put a std::map to much better use:
#include <algorithm>
#include <iterator>
#include <map>
template <typename Iterator>
bool has_duplicates( Iterator first, Iterator last )
{
std::map <typename std::iterator_traits <Iterator> ::value_type, std::size_t> histogram;
while (first != last)
if (++histogram[ *first++ ] > 1)
return true;
return false;
}
#include <iostream>
#include <vector>
int main()
{
using std::begin;
using std::end;
int a[] = { 2, 3, 5, 7, 11 };
int b[] = { 2, 3, 5, 5, 7 };
std::vector <int> c( begin(a), end(a) );
std::vector <int> d( begin(b), end(b) );
std::cout << std::boolalpha;
std::cout << "a has duplicates false : " << has_duplicates( begin(a), end(a) ) << "\n";
std::cout << "b has duplicates true : " << has_duplicates( begin(b), end(b) ) << "\n";
std::cout << "c has duplicates false : " << has_duplicates( begin(c), end(c) ) << "\n";
std::cout << "d has duplicates true : " << has_duplicates( begin(d), end(d) ) << "\n";
}
If your vector is small, say < 32 objects, or if copying and sorting the objects is expensive or impossible due to lack of move or copy constructor/assignment then a straight O(n^2) compare everything against everything else algorithm is the way to go.
Here is my solution:
template <typename Iterator>
bool has_duplicates( Iterator first, Iterator end ) {
for (auto i = first; i != end; ++i) {
for (auto j = first; i != j; ++j) {
if (*i == *j) return true;
}
}
return false;
}
template <typename Container>
bool has_duplicates(const Container &v) {
for (const auto & i : v) {
for (const auto & j : v) {
if (&i == &j) break;
if (i == j) return true;
}
}
return false;
}

Find string in vector of strings case insensitive c++

I have
std::vector<std::string> vec;
std::string myString;
and I need to find out if myString is in vec using case insensitive comaprisons.
I know I can use
find(vec.begin(), vec.end(), myString) != vec.end())
to answer the question "is myString in vec?" but that will do case sensitive comparisons. I need case insensitive comparisons.
The position is not important, I just want to know if myString is in vec or not.
You need to use std::tolower and std::find_if:
std::vector<std::string> vec = {"ALF", "B"};
std::string toSearch = "Alf";
auto itr = std::find_if(vec.begin(), vec.end(),
[&](auto &s) {
if ( s.size() != toSearch.size() )
return false;
for (size_t i = 0; i < s.size(); ++i)
if (::tolower(s[i]) == ::tolower(toSearch[i]))
return true;
return false;
}
);
if ( itr != vec.end()) {
std::cout << *itr << std::endl;
}
Or, for a much smaller and easier-to-read solution, Boost!
// #include <algorithm>
// #include <boost/algorithm/string/predicate.hpp>
const auto it = std::find_if(
std::begin(vec),
std::end(vec),
[&myString](const auto& str) { return boost::iequals(myString, str); }
);
const bool found = (it != std::end(vec));
You need to use std::find_if and provide a custom comparator. To achieve case insensitive comparison I would advise you to convert both strings you want to compare to a common case: lower or upper. That would lead to a code like the following:
auto ret = std::find_if(vec.begin(), vec.end(),
[&myString](const std::string& s) {
if (s.size() != myString.size())
return false;
return std::equal(s.cbegin(), s.cend(), myString.cbegin(), myString.cend(), [](auto c1, auto c2) { return std::toupper(c1) == std::toupper(c2); });
});
This will return an iterator which will be vec.end() if no occurrence of myString was found. You can do whatever you please with that iterator (including comparing it to vec.end() to know if you found your string).
Bonus: running minimal example on Coliru
You may use std::find_if, an inline lambda and std::tolower to make the comparison:
//Computing the lower version of mystring
std::string my_string_lower;
my_string_lower.reserve(mystring.size());
std::transform(mystring.begin(), mystring.end(), std::back_inserter(my_string_lower), ::tolower);
// Checking if it is exist in the vector:
auto is_exist = std::find_if(vec.begin(), vec.end(), [&my_string_lower](std::string item){
//Transform the each vector item to lower temporally
std::transform(item.begin(), item.end(), item.begin(), ::tolower);
return mystring==item;
}) != vec.end();
if you are going to search many times in the same vetor of string, it would be better if you compute it once:
//Computing the lower version of the whole vector
std::vector<std::string> vec_lower;
vec_lower.reserve(vec.size());
std::transform(vec.begin(), vec.end(), std::back_inserter(vec_lower),[](std:string item){
std::transform(item.begin(), item.end(), item.begin(), ::tolower);
return item;
});
//Computing the lower version of mystring
std::string my_string_lower;
my_string_lower.reserve(mystring.size());
std::transform(mystring.begin(), mystring.end(), std::back_inserter(my_string_lower), ::tolower);
// Checking if it is exist in the lower version of the vector:
auto is_exist = std::find_if(vec_lower.begin(), vec_lower.end(), [&my_string_lower](const std::string& item){
return mystring==item;
}) != vec_lower.end();
template <class T>
long VecFindIgnoreCase( const std::vector< T >& vec, const std::string& sFind ) {
return VecFindIgnoreCase( vec, sFind.c_str() );
}
template <class T>
long VecFindIgnoreCase( const std::vector< T >& vec, const char* sFind )
{
for ( std::vector< T >::const_iterator iter = vec.begin(); iter != vec.end(); ++iter )
if ( _stricmp( (*iter).c_str(), sFind ) == 0 )
return (long)std::distance( vec.begin(), iter );
return -1;
}
template <class T>
long VecFindIgnoreCase( const std::vector< T >& vec, const std::wstring& sFind ) {
return VecFindIgnoreCase( vec, sFind.c_str() );
}
template <class T>
long VecFindIgnoreCase( const std::vector< T >& vec, const wchar_t* sFind )
{
for ( std::vector< T >::const_iterator iter = vec.begin(); iter != vec.end(); ++iter )
if ( _wcsicmp( (*iter).c_str(), sFind ) == 0 )
return (long)std::distance( vec.begin(), iter );
return -1;
}
Use:
#include <string>
#include <vector>
void TestCode()
{
std::vector< std::string > strvecA;
std::vector< std::wstring > strvecW;
strvecA.push_back("abc");
strvecA.push_back("def");
strvecA.push_back("ghi");
strvecW.push_back(L"abc");
strvecW.push_back(L"def");
strvecW.push_back(L"ghi");
long ind;
ind = VecFindIgnoreCase( strvecA, "ABC" ); // ind = 0 found
ind = VecFindIgnoreCase( strvecA, "ghI" ); // ind = 2 found
ind = VecFindIgnoreCase( strvecA, "Xyz" ); // ind = -1 not found
ind = VecFindIgnoreCase( strvecW, L"aBc" ); // ind = 0 found
ind = VecFindIgnoreCase( strvecW, L"DEF" ); // ind = 1 found
ind = VecFindIgnoreCase( strvecW, L"xyZ" ); // ind = -1 not found
std::string sFind( "mno" );
if ( (ind = VecFindIgnoreCase( strvecA, sFind )) >= 0 ) {
// found at strvecA[ind]
} else {
// not found
}
}
Since the performance of std::find is better than std::count, I have to implement a function template to search in std::vector :
template <class Iterator>
Iterator Find(Iterator first, Iterator last, const char *value)
{
while (first != last)
{
if (StrCmpIA((*first).c_str(), value) == 0)
{
return first;
}
first++;
}
return last;
}
Now you can use of the template function like this :
vector<string> vecStr = {"ali", "reza", "hamid", "saeed"};
if (Find(vecStr.begin(), vecStr.end(), "saeeD") != vecStr.end())
{
cout << "found" << endl;
}
else
{
cout << "not found" << endl;
}

Splitting an STL list based on a condition

I have an std::list which looks as follows (the x marks indicate some number less than 500)
x,x,x,x,503,x,x,x,510,x,x,x,502,x,x,x,x,x,x,600 - std::list<int> originallist
I am looking to split the list into a vector of lists std::vector<std::list<int> > as follows
1st element of vector: x,x,x,x,503
2nd element of vector: x,x,x,510
...
...
last element of vector: x,x,x,x,x,x,600
The code I have now is as follows:
list<int> templist; vector<list<int> > v;
for(list<int>::iterator lit=originallist.begin(); lit!=oriniallist.end(); ++lit) {
if (*lit > 500) {
templist.push_back(*lit);v.push_back(templist); templist.clear(); continue;
}
templist.push_back(*lit);
}
What is the most efficient way to achieve the above task in c++ without using templist. Any help is appreciated.
While this solution does use a temporary std::list, it allocates no list node elements, and does exactly 1 memory allocation in the C++03 case (the C++11 case does a logarithmic number of memory allocations on the size of the return value)
This is a C++03 solution. A C++11 solution can do this in one pass.
bool big_as_500( int x ) {return x>=500;}
std::vector< std::list< int > > do_stuff( std::list<int>& original_list ) {
// we have to do this, because resizing the return value involves lots of allocations
// and stuff in C++03, so make sure we get the size right by precalculating it:
std::size_t count = std::count_if( originallist.begin(), originallist.end(), big_as_500 );
std::vector< std::list< int > > result;
result.reserve(count+1);
typedef std::list<int>::const_iterator const_iterator;
std::list< int > current;
for(const_iterator it= originallist.begin(); it!=originallist.end();/*nothing*/) {
++it; // about to invalidate it! (or move lists)
current.splice( current.end(), originallist, originallist.begin() ); // O(1) no memory allocation
if (big_as_500(current.back())) {
result.push_back( std::list<int>() );
current.swap( result.back() );
}
}
// original problem does not specify what to do if the original list does not end
// with an element "big_as_500", so I'll just drop them
return result; // rely on NRVO to eliminate the copy here, if your compiler does not
// support it, take result as a reference parameter.
}
A C++11 solution:
std::vector< std::list< int > > do_stuff( std::list<int>& original_list ) {
std::vector< std::list< int > > result;
typedef std::list<int>::const_iterator const_iterator;
std::list< int > current;
for(const_iterator it= originallist.begin(); it!=originallist.end();/*nothing*/) {
++it;// about to become invalid/in wrong list
current.splice( current.end(), originallist, originallist.begin() ); // O(1) no memory allocation
if (current.back() >= 500) {
result.emplace_back( std::move(current) );
}
}
// original problem does not specify what to do if the original list does not end
// with an element "big_as_500", so I'll just drop them
return result; // will NRVO, or move, so no worries
}
in C++11, resizes are relatively cheap, so we are good.
Now, we could get really fancy in C++03 and emulate what C++11 does and do it all in one pass.
template<typename T, typename A>
void efficient_grow_by_1( std::vector<T,A>& make_one_bigger ) {
if (make_one_bigger.size()+1 > make_one_bigger.capacity() )
{
std::vector<T, A> swap_vec;
swap_vec.reserve( (make_one_bigger.size()+1)*5/3 );
for (std::vector<T, A>::iterator it = make_one_bigger.begin(); it != make_one_bigger.end(); ++it ) {
using std::swap;
swap_vec.push_back();
std::swap( *it, swap_vec.back() );
}
swap_vec.swap( make_one_bigger );
}
make_one_bigger.push_back();
}
void do_stuff( std::list<int>& original_list, std::vector< std::list< int > >& result ) {
typedef std::list<int>::const_iterator const_iterator;
std::list< int > current;
for(const_iterator it= originallist.begin(); it!=originallist.end();) {
++it;
current.splice( current.end(), originallist, originallist.begin() ); // O(1) no memory allocation
if (current.back()>=500) {
efficient_grow_by_1(result);
current.swap( result.back() );
}
}
// original problem does not specify what to do if the original list does not end
// with an element "big_as_500", so I'll just drop them
}
which is rather insane, so I'd advise upgrading your compiler.
The trick here is that we populate the 'temporary' list with a single-element-at-a-time splice. Because (most? many?) implementations of std::list::splice end up having to walk over the elements to count them (it is required in C++11, and common in C++03), doing it one at a time as we determine which elements we want to put into the next chunk is reasonably efficient. Each node comes directly from the input list, and is collected into the temporary list (no memory allocations).
Once we have built up this list, we directly swap it into the output vector of lists. This avoids any memory allocations, other than that which is required to hold the (relatively small) base data of the list.
In C++03, we either do a two-pass solution and pre calculate how big the output std::vector is, or we emulate C++11 move efficiency with careful growth and swap mechanics on the contained lists. It is possible that your std library implementation fakes this already, but I am unsure how common swap-resize optimization was in the old libraries.
Keeping things down to a single pass is probably worth the logarithmic number of allocations that the 2nd C++03 and C++11 solutions use: walking a std::list is an exercise in cache misses.
Third version
This version uses std::list::splice and moves iterator till delimiter is found or end() reached.
#include <iostream>
#include <list>
#include <vector>
std::vector< std::list<int> > & split( std::list<int> v,
int delim, std::vector< std::list<int> >& elems) {
auto it = v.begin();
while ( it != v.end()) {
std::list<int> l;
while ( it != v.end() && *it < delim) {
++it;
}
if( it != v.end()) {
l.splice( l.begin(), v, v.begin(), ++it);
it = v.begin();
} else {
l.splice( l.begin(), v, v.begin(), it);
}
elems.push_back( l);
}
return elems;
}
std::vector< std::list<int> > split( const std::list<int> &v, int delim) {
std::vector< std::list<int> > elems;
split( v, delim, elems);
return elems;
}
usage:
int main() {
std::list<int> v = { 1, 2, 3, 503, 5, 6, 502, 7, 510, 3, 500, 6, 7};
std::vector< std::list<int> > vl;
vl = split( v, 500);
int i = 0;
while( i < vl.size()) {
std::list<int>::const_iterator it = vl[ i].begin();
while( it != vl[ i].end())
std::cout << *it++;
std::cout << std::endl;
++i;
}
return 0;
}
http://ideone.com/VRpGft
prints:
123503
56502
7510
3500
67
First version
This version uses std::list::splice.
#include <iostream>
#include <list>
#include <vector>
std::vector< std::list<int> > & split( std::list<int> v,
int delim, std::vector< std::list<int> >& elems) {
auto it = v.begin();
while ( it != v.end()) {
std::list<int> l;
auto it3 = l.begin();
while ( it != v.end() && *it < delim) {
l.splice( it3, v, it);
it = v.begin();
}
if( it != v.end()) {
l.splice( it3, v, it);
it = v.begin();
}
elems.push_back( l);
}
return elems;
}
std::vector< std::list<int> > split( const std::list<int> &v, int delim) {
std::vector< std::list<int> > elems;
split( v, delim, elems);
return elems;
}
usage:
int main() {
std::list<int> v = { 1, 2, 3, 503, 5, 6, 502, 7, 510, 3, 500, 5, 9};
std::vector< std::list<int> > vl;
vl = split( v, 500);
int i = 0;
while( i < vl.size()) {
std::list<int>::const_iterator it = vl[ i].begin();
while( it != vl[ i].end())
std::cout << *it++;
++i;
}
return 0;
}
prints:
123503565027510350059
http://ideone.com/1xMehy
Second version
This is simplified version that doesn't use std::list::splice function. This function puts elements before the iterator so the loop would have to be slightly changed.
#include <iostream>
#include <list>
#include <vector>
std::vector< std::list<int> > & split( const std::list<int> & v,
int delim, std::vector< std::list<int> >& elems) {
std::list<int>::const_iterator it = v.begin();
while ( it != v.end()) {
std::list<int> l;
while ( it != v.end() && *it < delim) {
l.push_back( *it++);
}
if( it != v.end()) l.push_back( *it++);
elems.push_back( l);
}
return elems;
}
std::vector< std::list<int> > split( const std::list<int> &v, int delim) {
std::vector< std::list<int> > elems;
split( v, delim, elems);
return elems;
}
usage:
int main() {
std::list<int> v = { 1, 2, 3, 503, 5, 6, 502, 7, 510, 3, 500, 5, 9};
std::vector< std::list<int> > vl;
vl = split( v, 500);
int i = 0;
while( i < vl.size()) {
std::list<int>::const_iterator it = vl[ i].begin();
while( it != vl[ i].end())
std::cout << *it++;
++i;
}
return 0;
}
prints:
123503565027510350059
http://ideone.com/MBmlLE
Try the following
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
//...
auto first = YourList.begin();
while ( first != YourList.end() )
{
auto last = std::find_if( first, YourList.end(), std::bind2nd( std::greater<int>(), 500 ) );
if ( last != YourList.end() ) ++last;
YourVector.push_back( std::list<int>( first, last ) );
first = last;
}
Loop through the numbers and get the distance between the locations where you need to split the list.
Use the splice function in List for each split location:
lst.splice( newLst.begin(), newLst, lst.begin(), lst.begin() + sliceLength);
http://www.cplusplus.com/reference/list/list/splice/
(Note that splice will destroy the original list)

Map doesn't sort with regard to comparator c++

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

Erase/Remove contents from the map (or any other STL container) while iterating it

Allegedly you cannot just erase/remove an element in a container while iterating as iterator becomes invalid. What are the (safe) ways to remove the elements that meet a certain condition? please only stl, no boost or tr1.
EDIT
Is there a more elegant way if I want to erase a number of elements that meet a certain criteria, perhaps with using functor and for_each or erase algorithm ?
You can as long as you don't invalidate your iterator after you've erased it:
MyContainer::iterator it = myContainer.begin();
while(it != myContainer.end())
{
if (*it == matchingValue)
{
myContainer.erase(it++);
}
else
{
++it;
}
}
Example with std::vector
#include <vector>
using namespace std;
int main()
{
typedef vector <int> int_vector;
int_vector v(10);
// Fill as: 0,1,2,0,1,2 etc
for (size_t i = 0; i < v.size(); ++i){
v[i] = i % 3;
}
// Remove every element where value == 1
for (int_vector::iterator it = v.begin(); it != v.end(); /* BLANK */){
if (*it == 1){
it = v.erase(it);
} else {
++it;
}
}
}
bool IsOdd( int i )
{
return (i&1)!=0;
}
int a[] = {1,2,3,4,5};
vector<int> v( a, a + 5 );
v.erase( remove_if( v.begin(), v.end(), bind1st( equal_to<int>(), 4 ) ), v.end() );
// v contains {1,2,3,5}
v.erase( remove_if( v.begin(), v.end(), IsOdd ), v.end() );
// v contains {2}
Viktor's solution has the upside of being able to do something with the element before removing. (I wasn't able to do this with remove_if or remove_copy_if.) But I prefer to use std::find_if so I never have to increment the iterator myself:
typedef vector<int> int_vector;
int_vector v;
int_vector::iterator itr = v.begin();
for(;;)
{
itr = std::find_if(itr, v.end(), Predicate(4));
if (itr == v.end())
{
break;
}
// do stuff with *itr here
itr = v.erase(itr); // grab a new, valid iterator
}
Where Predicate could be bind1st( equal_to<int>(), 4 ) or something like this:
struct Predicate : public unary_function<int, bool>
{
int mExpected;
Predicate(int desired) : mExpected(desired) {}
bool operator() (int input)
{
return ( input == mExpected );
}
};
I prefer version with while:
typedef std::list<some_class_t> list_t;
void f( void ) {
// Remove items from list
list_t::iterator it = sample_list.begin();
while ( it != sample_list.end() ) {
if ( it->condition == true ) {
it = sample_list.erase( it );
} else ++it;
}
}
With while there is no danger to increment it twice as it could be in for loop.
1.For std::vector<> :
std::vector <int> vec;
vec.erase(std::remove(vec.begin(),vec.end(), elem_to_remove), vec.end());
2.For std::map<> always use std::map::erase()
std::map<int,std::string> myMap;
myMap.emplace(std::make_pair(1, "Hello"));
myMap.emplace(std::make_pair(2, "Hi"));
myMap.emplace(std::make_pair(3, "How"));
myMap.erase( 1);//Erase with key
myMap.erase(myMap.begin(), ++myMap.begin() );//Erase with range
for( auto &ele: myMap)
{
if(ele.first ==1)
{
myMap.erase(ele.first);//erase by key
break; //You can't use ele again properly
//wthin this iteration, so break.
}
}
For std::list use std::list::erase()
markh44 is the most STL-ish response.
Note, however, that in general, iterators are invalidated by modifying the container, but set and map are exceptions. There, you can remove items and still go on using the iterators, except if you delete the very item your iterator is referencing.
Use the fact that the post-decrement operator returns a copy of the iterator before it decrements. Since the decremented iterator is still valid after erasing the current element, the for loop continues to operate as intended.
#include <list>
std::list<int> myList;
for(int i = 0; i < 10; ++i )
{
myList.push_back(i);
}
int cnt = 0;
for(std::list<int>::iterator iter = myList.begin(); iter != myList.end(); ++iter)
{
if( cnt == 5 )
{
myList.erase(iter--);
}
++cnt;
}
Edit: Doesn't work if you attempt to erase the first element in the list....
template <class Container, class Predicate>
void eraseIf( Container& container, Predicate predicate ) {
container.erase( remove_if( container.begin(), container.end(), predicate ), container.end() );
}
// pre-c++11 version
template<class K, class V, class Predicate>
void eraseIf( std::map<K,V>& container, Predicate predicate) {
typename std::map<K,V>::iterator iter = container.begin();
while(iter!=container.end()) {
iterator current = iter++;
if(predicate(*current))
container.erase(current);
}
}
// c++11 version
template<class K, class V, class Predicate>
void eraseIf( std::map<K,V>& container, Predicate predicate) {
auto iter = container.begin();
while(iter!=container.end()) {
if(predicate(*iter))
iter = container.erase(iter);
else
++iter;
}
}