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)
Related
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;
}
I have this function that is suppose to return all possible permutation of integers inside the vector. The code is based from an existing code that does a permutation of strings, I tried to remodeled it to work on vectors but apparently, they dont work similarly as I thought..
I'll appreciate any help that you could offer thanks;
vector<vector<int>> permute(vector<int> &v1, vector<int> &v2){
vector<vector<int>> v;
if( v1.empty() )
{
v.push_back(v2);
return v;
}
for(auto it = v1.begin(); it != v1.end(); it++){
vector<int> temp1 = v1;
temp1.erase(it); //there's a runtime error on this line
vector<int> temp2 = v2;
temp2.push_back(*it);
permute(temp1, temp2);
}
return v;
}
This is the original code that permutes a string.
void string_permutation( std::string& orig, std::string& perm )
{
if( orig.empty() )
{
std::cout<<perm<<std::endl;
return;
}
for(int i=0;i<orig.size();++i)
{
std::string orig2 = orig;
orig2.erase(i,1);
std::string perm2 = perm;
perm2 += orig.at(i);
string_permutation(orig2,perm2);
}
}
Here you go:
template < typename T>
void vec_permute( std::vector<T> &orig, std::vector<T> &perm)
{
if(orig.empty())
{
for( auto &x : perm)
std::cout<<x;
std::cout<<"\n";
return;
}
for(typename std::vector<T>::size_type i=0;i <orig.size();++i)
{
std::vector<T> orig2(orig);
orig2.erase(std::find(orig2.begin(),orig2.end(),orig.at(i)));
std::vector<T> perm2(perm);
perm2.push_back(orig.at(i));
vec_permute(orig2,perm2);
}
}
Demo: http://coliru.stacked-crooked.com/a/01ded4b778aa4165
Iterators can only be used with the container that you instanciated them with
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.
What basically I am doing is the set cover problem, removing duplicate from the vectors that has the same numbers. An example:
I have the following vectors of vectors after sorting:
{{1,2,3,4,5},{2,3,7,8},{10,11,12}}
NOW, I would like to remove the occurrence from 2nd vector which is 2,3 and sort again ...
{{1,2,3,4,5},{10,11,12},{7,8}}
I have implemented some code to sort the vectors of vectors but i have problem removing the occurrences from the vector that has less size?
The sort function:
sort(ROWS.begin(),ROWS.end(),VectorsSort());
Thanks for the help.
Pick this apart and take what you need:
#include <algorithm>
#include <vector>
struct binary_search_pred
{
typedef bool result_type;
explicit binary_search_pred(std::vector<int> const& v) : v_(&v) { }
bool operator ()(int const& i) const
{
return std::binary_search(v_->begin(), v_->end(), i);
}
private:
std::vector<int> const* v_;
};
struct size_comparison_desc
{
typedef bool result_type;
typedef std::vector<int> const& arg_t;
bool operator ()(arg_t a, arg_t b) const
{
return b.size() < a.size();
}
};
void set_cover(std::vector<std::vector<int> >& vec)
{
typedef std::vector<std::vector<int> > vec_t;
typedef vec_t::iterator iter_t;
typedef vec_t::const_iterator citer_t;
if (vec.empty() || vec.size() == 1)
return;
for (iter_t v = vec.begin() + 1, v_end = vec.end(); v != v_end; ++v)
for (citer_t p = vec.begin(); p != v; ++p)
v->erase(
std::remove_if(v->begin(), v->end(), binary_search_pred(*p)),
v->end()
);
std::sort(vec.begin(), vec.end(), size_comparison_desc());
}
(Note that set_cover requires that the contained std::vector<int>s given must already be sorted.)
EDIT #1:
As requested in now-deleted comments, a version oriented around std::map<int, std::vector<int>> instead of std::vector<std::vector<int>> (use binary_search_pred from the original code):
#include <algorithm>
#include <map>
#include <vector>
void set_cover(std::map<int, std::vector<int> >& m)
{
typedef std::map<int, std::vector<int> > map_t;
typedef map_t::iterator iter_t;
typedef map_t::const_iterator citer_t;
if (m.empty() || m.size() == 1)
return;
for (iter_t v = ++m.begin(), v_end = m.end(); v != v_end; ++v)
for (citer_t p = m.begin(); p != v; ++p)
v->second.erase(
std::remove_if(
v->second.begin(),
v->second.end(),
binary_search_pred(p->second)
),
v->second.end()
);
}
Note that the map here will always be sorted by its key, never by the contained vector's size (which is what you appear to want). Maybe you want a std::vector<std::pair<int, std::vector<int>>> instead?
EDIT #2:
As requested in now-deleted comments, a version oriented around std::vector<std::pair<int, std::vector<int>>> instead of std::map<int, std::vector<int>> (use binary_search_pred from the original code):
#include <algorithm>
#include <utility>
#include <vector>
struct size_comparison_desc
{
typedef bool result_type;
typedef std::pair<int, std::vector<int> > const& arg_t;
bool operator ()(arg_t a, arg_t b) const
{
return b.second.size() < a.second.size();
}
};
void set_cover(std::vector<std::pair<int, std::vector<int> > >& vec)
{
typedef std::vector<std::pair<int, std::vector<int> > > vec_t;
typedef vec_t::iterator iter_t;
typedef vec_t::const_iterator citer_t;
if (vec.empty() || vec.size() == 1)
return;
for (iter_t v = vec.begin() + 1, v_end = vec.end(); v != v_end; ++v)
for (citer_t p = vec.begin(); p != v; ++p)
v->second.erase(
std::remove_if(
v->second.begin(),
v->second.end(),
binary_search_pred(p->second)
),
v->second.end()
);
std::sort(vec.begin(), vec.end(), size_comparison_desc());
}
You shouldn't need to define a vector sorting predicate. Vector already defines an operator< which is based on std::lexicographical_compare.
Is this what you mean?
std::for_each(rows.begin(), rows.end(), [](std::vector<int>& row) {
row.erase(std::remove_if(row.begin(), row.end(), [](int number) -> bool {
return (number == 2) || (number == 3);
}), row.end());
});
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;
}
}