Removing elements of 2D vector - c++

I have a 2D vector and I need to remove blocks that do not contain sufficient values:
typedef vector<double> iniMatrix;
bool hasInsufficientEnergy() {
return true;
}
vector<double> Audio::filter(vector<iniMatrix>&blocks, double sumThres, double ZeroThres)
{
vector<double> totalEnergy;
vector<double> totalZeroCross;
double totalSum = sumThres * blocks.size();
double totalZero = ZeroThres * blocks.size();
vector<iniMatrix> blockked;
for(unsigned i=0; (i < blocks.size()); i++)
{
totalEnergy.push_back(abs(this->energy(blocks[i])));
totalZeroCross.push_back(zerocross(blocks[i]));
if(!totalEnergy[i] > totalSum || totalZeroCross[i] < ZeroThres)
{
hasInsufficientEnergy();
}else{
//hasInsufficientEnergy();
}
iniMatrix::iterator erase_after = remove_if(blocks[i].begin(), blocks[i].end(),
&hasInsufficientEnergy);
}
}
The problem is erase_after and comes up with an error message:
In function ‘_OutputIterator std::remove_copy_if(_InputIterator, _InputIterator,
_OutputIterator, _Predicate) [with _InputIterator = __gnu_cxx::__normal_iterator<double*,
std::vector<double, std::allocator<double> > >, _OutputIterator =
__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >,
_Predicate = bool]’:
/usr/include/c++/4.2.1/bits/stl_algo.h:1302: instantiated from ‘_ForwardIterator
std::remove_if(_ForwardIterator, _ForwardIterator, _Predicate) [with _ForwardIterator =
__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >,
_Predicate = bool]’
Audio.cpp:105: instantiated from here
/usr/include/c++/4.2.1/bits/stl_algo.h:1227: error: ‘__pred’ cannot be used as a function
Anyone have any ideas to where I am going wrong?

The third argument to std::remove_if is a predicate function (or any callable entity, for that matter) that takes a single element and returns true if it needs to be removed and false if not. The element of a vector of vectors (or "2D vector", as you call it) is a vector, vector<double> in your case. That's what the argument to your predicate should be:
bool HasInsufficientEnergy(const vector<double>& elem)
{
// herein is the code that tests elem and decides
// whether it should be removed or not
}
Then your filter() method shouldn't contain much more than this
void Audio::filter(vector<iniMatrix>&blocks)
{
auto it = std::remove_if(blocks.begin(), blocks.end(), &HasInsufficientEnergy);
blocks.erase(it, blocks.end());
}
If your predicate needs aditional arguments, then implement it as a class that takes them as constructor parameters. You need to overload operator(), too, so you have a callable functor.
If your compiler supports C++11, then learn how to use lambda functions as they are very useful for exactly this task.

true or false aren't function objects. If you want to use remove_if you must give it a pointer to function or function object, which takes a member of the collection as parameter and returns whether to remove it or not. Look at the example in std::remove_if
AFAICS, you could replace the remove_if/erase into the if and simplify it to:
for(auto i=blocks.begin(); i != blocks.end(); )
{
totalEnergy.push_back(abs(this->energy(*i)));
totalZeroCross.push_back(zerocross(*i));
if(!totalEnergy.rbegin() > totalSum || totalZeroCross.rbegin() < ZeroThres)
{
i = blocks.erase(i);
} else {
++i;
}
}

remove_if, and similar algorithms, expect a function, not a value, i.e. you should pass a function pointer or functor that an double const & and returns a bool
bool hasInsufficientEnergy(double const & element) {
// return true if it should be removed, false otherwise
}
and then
iniMatrix::iterator erase_after = remove_if(blocks[i].begin(), blocks[i].end(),
&hasInsufficientEnergy);
will work

Related

const arguments in std::remove_if

I'm going to remove elements from a list of pairs. When I'm using a pair like
std::pair<const int, bool>
I get the following compilation error:
In file included from /usr/local/include/c++/6.1.0/utility:70:0,
from /usr/local/include/c++/6.1.0/algorithm:60,
from main.cpp:1:
/usr/local/include/c++/6.1.0/bits/stl_pair.h: In instantiation of
'std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1,
_T2>&&) [with _T1 = const int; _T2 = bool]':
/usr/local/include/c++/6.1.0/bits/stl_algo.h:868:16: required from
'_ForwardIterator std::__remove_if(_ForwardIterator, _ForwardIterator,
_Predicate) [with _ForwardIterator = std::_List_iterator > _Predicate =
__gnu_cxx::__ops::_Iter_pred&)> >]'
/usr/local/include/c++/6.1.0/bits/stl_algo.h:936:30: required from
'_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter =
std::_List_iterator > _Predicate =
main()::&)>]'
main.cpp:17:32: required from here
/usr/local/include/c++/6.1.0/bits/stl_pair.h:319:8: error: assignment
of read-only member 'std::pair::first'
first = std::forward(__p.first);
This is the sample code:
int main()
{
int id = 2;
std::list< std::pair <const int, bool> > l;
l.push_back(std::make_pair(3,true));
l.push_back(std::make_pair(2,false));
l.push_back(std::make_pair(1,true));
l.erase(std::remove_if(l.begin(), l.end(),
[id](std::pair<const int, bool>& e) -> bool {
return e.first == id; }));
for (auto i: l) {
std::cout << i.first << " " << i.second << std::endl;
}
}
I know that (please correct me If I am wrong):
I will have exactly the same problem as long as there is constness in any element of the list, for example, a list <const int> will also return a compilation error.
If I remove the const in the first element of the pair the code will work.
The more elegant and efficient way to do it is by using the remove_if list method, like this:
l.remove_if([id](std::pair<const int, bool>& e) -> bool {
return e.first == id; });
but my question is, what are exactly the inner workings of std::remove_if that impose the elements of the container not being const?
The general std::remove_if shuffles item values around to put the logically erased values at the end of the sequence (it's typically used in combination with member function erase to actually remove the logically erased values). It can't do that shuffling when an item isn't copyable or movable. Instead use std::list::remove_if.
If you look at the type and iterator requirements of std::remove_if, you can see that the implementation must be similar to the following (from the link above):
template<class ForwardIt, class UnaryPredicate>
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
first = std::find_if(first, last, p);
if (first != last)
for(ForwardIt i = first; ++i != last; )
if (!p(*i))
*first++ = std::move(*i);
return first;
}
I.e., the algorithm assumes only that the iterators have forward capabilities, and elements are moveable, and it moves elements around. Of course, moves can't be done on const objects.

map, lambda, remove_if

So, i've problem with std::map, lambda and stl algorithm(remove_if). Actually, same code with std::list or std::vector works well.
My test example :
#include <map>
#include <iostream>
#include <algorithm>
struct Foo
{
Foo() : _id(0) {}
Foo(int id) : _id(id)
{
}
int _id;
};
typedef std::map<int, Foo> FooMap;
int main()
{
FooMap m;
for (int i = 0; i < 10; ++i)
m[i + 100] = Foo(i);
int removeId = 6;
// <<< Error here >>>
std::remove_if(m.begin(), m.end(), [=](const FooMap::value_type & item) { return item.second._id == removeId ;} );
for (auto & item : m )
std::cout << item.first << " = " << item.second._id << "\n";
return 0;
}
Error message :
In file included from /usr/include/c++/4.6/utility:71:0,
from /usr/include/c++/4.6/algorithm:61,
from main.cxx:1:
/usr/include/c++/4.6/bits/stl_pair.h: In member function ‘std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1, _T2>&&) [with _T1 = const int, _T2 = Foo, std::pair<_T1, _T2> = std::pair<const int, Foo>]’:
/usr/include/c++/4.6/bits/stl_algo.h:1149:13: instantiated from ‘_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = std::_Rb_tree_iterator<std::pair<const int, Foo> >, _Predicate = main()::<lambda(const value_type&)>]’
main.cxx:33:114: instantiated from here
/usr/include/c++/4.6/bits/stl_pair.h:156:2: error: assignment of read-only member ‘std::pair<const int, Foo>::first’
I don't understand what's wrong here. So, i gladly to read some advices/directions about it. My goal - use new lambda-style with std::map and algorithms, such as remove_if.
g++ 4.6, -std=c++0x.
The problem is that std::map<K,V>::value_type is std::pair<const K, V>, aka .first is const and not assignable. Lambdas have nothing to do with the problem here.
std::remove_if "removes" items by moving the elements of the container around, so that everything that does not fit the predicate is at the front, before the returned iterator. Everything after that iterator is unspecified. It does that with simple assignment, and since you can't assign to a const variable, you get that error.†
The name remove can be a bit misleading and in this case, you really want erase_if, but alas, that doesn't exist. You'll have to make do with iterating over all items and erasing them by hand with map.erase(iterator):
for(auto it = map.begin(), ite = map.end(); it != ite;)
{
if(it->second._id == remove_id)
it = map.erase(it);
else
++it;
}
This is safe because you can erase individual nodes in the tree without the other iterators getting invalidated. Note that I did not increment the iterator in the for loop header itself, since that would skip an element in the case where you erase a node.
† By now, you should have noticed that this would wreak havoc in the std::map's ordering, which is the reason why the key is const - so you can't influence the ordering in any way after an item has been inserted.
You could use find and erase for the map. It's not as convenient as remove_if, but it might be the best you've got.
int removeId = 6;
auto foundIter = m.find(removeId);
// if removeId is not found you will get an error when you try to erase m.end()
if(foundIter != m.end())
{
m.erase(foundIter);
}

C++ STL wrong keys types

can't understand this: g++ compiler is angry on:
lengths.insert(pair<Deux,long>(d,one));
where
struct Deux {long big; long small};
map<Deux, long> lengths;
Deux d;
long one;
so, g++ said, that i miss operator<. after making overloaded operator< for struct Deux, i saw new interesting, but the same error:
map <long, Node*>ArrayOfNodes;
map <long, Node*>::iterator it;
for (it=ArrayOfNodes[Root]->nodes.begin();it<ArrayOfNodes[Root]->nodes.end();++it)
cout<<it->first<<endl;
also used structure Node:
struct Node {
long name;
long guest;
map <long,Node*>nodes;
/*bool operator<(const Node& node)const{
if ((*this).name<node.name) return true;
if ((*this).name>node.name) return false;
return (*this).guest<(*this).guest;
}*/
and error is:
no match for operator< in it < ((Path*)this)->Path::ArrayOfNodes.
std::map<_Key, _Tp, _Compare, _Alloc>::operator[] [with _Key = long int, _Tp = Node*,
_Compare = std::less<long int>, _Alloc = std::allocator<std::pair<const long int, Node*> >]
(((const long int&)((const long int*)(&((Path*)this)->Path::Root))))->Node::nodes.std::map<_Key, _Tp, _Compare, _Alloc>::end
[with _Key = long int, _Tp = Node*, _Compare = std::less<long int>, _Alloc = std::allocator<std::pair<const long int, Node*> >]()
The compiler complains that there is no operator < for Deux (I guess). The key must be a comparable class with operator < or you must pass a third template parameter to map - the comparator.
You see, the map keeps its keys in an ordered way. In order to order them, it needs a predicate. By default it tries to use operator <
try writing something like this:
bool operator < (Deux const & d1, Deux const & d2)
{
if(d1.big > d2.big)
return false;
if(d1.big < d2.big)
return true;
return d1.small < d2.small;
}
You did not mention the error message. Always post it!
So, I need to fork my post into two distinct sections.
Missing Declaration.
`error: 'Deux' was not declared in this scope`
That's because Deux is unknown at the point where you declare the map<>.
You need to declare Deux before map<Deux, long>, because map<Deux, long> requires the full definition of its parameters.
Missing Comparator.
`error: no match for 'operator<' in '__x < __y'`
That's because you haven't defined operator< for Deux.`
If you can define a logical operator<, i.e. one that is not arbitrarily chosen for sorting purposes, you could do it like this:
// must be in same namespace as Deux
bool operator< (Deux const &lhs, Deux const &rhs) {
return lhs.foo < rhs.foo;
}
If it needs access to non-public members, you can make it a member function:
bool operator< (Deux const &rhs) {
return this->foo < rhs.foo;
}
If such comparison would be arbitrary, do as Constantinius suggests.
Next time
You could have saved us time by posting your actual code or a minimal testcase, as well as by mentioning the error message.
My guess is that your struct is missing a compare function, to make an internal sorting of your Deux objects as keys. In a map, they have to be sorted.
This is the definition of std::map
template < class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key,T> > > class map;
So if you define a function like this:
bool compare_deux(Deux& a, Deux& b) {
return a.big < b.big;
}
and pass it as a template argument:
map <Deux, long, compare_deux> lengths;
you should be fine.
Use make_pair.
lengths.insert(make_pair<Deux,long>(d,one));
Just to add yet another reply, here's how I would implement Deux to be strictly ordered. We just use lexicographic ordering:
struct Deux
{
long big, small;
inline bool operator<(const Deux & o) const
{
return big < o.big || (!(o.big < big) && small < o.small);
}
};
std::map<Deux, T> m; // works now!
Alternatively, we could have spared ourselves the pain and said:
typedef std::pair<long, long> Deux;
std::map<Deux, T> m; // always works, lexicographic compare is provided by default
Always best not to reinvent the wheel!
Post a comment if you also want pair hashing using hash_combine to use unordered containers.
You need to declare the < operator or pass a comparison function on map creation.
struct Deux
{
long big;
long small
bool operator < (const Deux &n) const
{
if(big != n.big)
return big < n.big;
else
return small < n.small;
}
};

Errors when using map() in C++

I wrote a piece of code and used map and vector but it shows me something I can't get. I'll be thankful if someone help me in this way and correct my code or give me some hints.
The code is:
// For each node in N, calculate the reachability, i.e., the
// number of nodes in N2 which are not yet covered by at
// least one node in the MPR set, and which are reachable
// through this 1-hop neighbor
std::map<int, std::vector<const NeighborTuple *> > reachability;
std::set<int> rs;
for (NeighborSet::iterator it = N.begin(); it != N.end(); it++)
{
NeighborTuple const &nb_tuple = *it;
int r = 0;
for (TwoHopNeighborSet::iterator it2 = N2.begin (); it2 != N2.end (); it2++)
{
TwoHopNeighborTuple const &nb2hop_tuple = *it2;
if (nb_tuple.neighborMainAddr == nb2hop_tuple.neighborMainAddr)
r++;
}
rs.insert (r);
reachability[r].push_back (&nb_tuple);
}
/*******************************************************************************/
//for keepping exposition of a node
std::map<Vector, std::vector<const NeighborTuple *> > position;
std::set<Vector> pos;
for (NeighborSet::iterator it = N.begin(); it != N.end(); it++)
{
NeighborTuple nb_tuple = *it;
Vector exposition;
pos.insert (exposition);
position[exposition].push_back (&nb_tuple);
}
and the errors are for this line: position[exposition].push_back (&nb_tuple);
and the errors are:
/usr/include/c++/4.1.2/bits/stl_function.h: In member function ‘bool std::less<_
Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = ns3::Vector3D]’:
/usr/include/c++/4.1.2/bits/stl_map.h:347: instantiated from ‘_Tp& std::map<_K
ey, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = ns3::Vector3D, _Tp = std::vector<const ns3::olsr::NeighborTuple*, std::allocator<const ns3::olsr::NeighborTuple*> >, _Compare = std::less<ns3::Vector3D>, _Alloc = std::allocator<std::pair<const ns3::Vector3D, std::vector<const ns3::olsr::NeighborTuple*, std::allocator<const ns3::olsr::NeighborTuple*> > > >]’
../src/routing/olsr/olsr-routing-protocol.cc:853: instantiated from here
/usr/include/c++/4.1.2/bits/stl_function.h:227: error: no match for ‘operator<’ in ‘__x < __y’
debug/ns3/ipv6-address.h:432: note: candidates are: bool ns3::operator<(const ns3::Ipv6Address&, const ns3::Ipv6Address&)
debug/ns3/nstime.h:475: note: bool ns3::operator<(const ns3::Time&, const ns3::Time&)
debug/ns3/ipv4-address.h:305: note: bool ns3::operator<(const ns3::Ipv4Address&, const ns3::Ipv4Address&)
debug/ns3/address.h:231: note: bool ns3::operator<(const ns3::Address&, const ns3::Address&)
debug/ns3/type-id.h:376: note: bool ns3::operator<(ns3::TypeId, ns3::TypeId)
Thanks in advance.
Bahar
std::map is a sorted container of pairs. As such, keys in the map must have operator <() defined. Make sure Vector has the less-than operator defined.
For example:
class Vector {
int len, ang;
friend bool operator<(const Vector&, const Vector&);
};
bool operator<(const Vector& v1, const Vector& v2)
{
return true_if_v1_is_less_than_v2(); // you define what "less than" means
}
Of course, there other ways to do this. You may make operator< a member function. Or you may have the two member data public and the operator a non-member, non-friend function. Or you may define operator< in an anonymous namespace, to enhance information hiding. Or you may use a comparator other than operator<.
You declared the position object as followed : std::map<Vector, std::vector<const NeighborTuple *> > position;
And you are trying to push NeighborTuple * inside...
Try using const NeighborTuple *
I notice that you seem to have a pushback line that compiles and a line that does not.
The difference might be that you have a const in the first case
NeighborTuple const &nb_tuple = *it;

how to pass a stl vector to a function which takes a const [] (c++)

i have a 3d stl vector,
vector<vector<vector<double> > > mdata;
i also have a function
myfun(const double ya[]);
to be more precise, it's a function from the GNU Scientific Library,
gsl_spline_init(gsl_spline * spline, const double xa[], const double ya[], size_t size);
but this is not related to my problem.
so now i want to pass the 'last' dimension of data to myfun. i've been trying this:
for (int s = 0; s < msize; s++) {
accelerators = new gsl_interp_accel*[msize];
splines = new gsl_spline*[msize];
for (int i = 0; i < msize; i++) {
accelerators[i] = gsl_interp_accel_alloc();
splines[i] = gsl_spline_alloc(gsl_interp_cspline_periodic, msize+1);
gsl_spline_init(splines[i], &(*mgrid.begin()), &(*mdata[s][i].begin()), msize+1);
}
}
But the compiler (g++, 64bit, Ubuntu), complains:
In member function
‘std::vector<std::vector<std::vector<double,
std::allocator<double> >,
std::allocator<std::vector<double,
std::allocator<double> > > >,
std::allocator<std::vector<std::vector<double,
std::allocator<double> >,
std::allocator<std::vector<double,
std::allocator<double> > > > > >
SimpleAmfCalculator::interp_m(int)’:
Calculator.cpp:100: error: cannot
convert ‘std::vector<double,
std::allocator<double> >*’ to ‘const
double*’ for argument ‘3’ to ‘int
gsl_spline_init(gsl_spline*, const
double*, const double*, size_t)’ make:
*** [Calculator.o] Error 1
Any help is greatly apprecitated!
You could pass the address of the first element, for example:
#include <vector>
void fun(const double data[])
{
}
int main()
{
std::vector<std::vector<std::vector<double> > > data3d;
....
fun(&data3d[0][0][0]);
}
The elements of vector are stored contiguously. So this way is standard as I hope :)
23.2.4 Class template vector
1 A vector is a kind of
sequence that supports random access
iterators. In addition, it supports
(amortized) constant time insert and
erase operations at the end; insert
and erase in the middle take linear
time. Storage management is handled
automatically, though hints can be
given to improve efficiency. The
elements of a vector are stored
contiguously, meaning that if v is a
vector where T is some
type other than bool, then it obeys
the identity:
&v[n] == &v[0] + n for
all 0 <= n < v.size().
This cries out for a general solution.
template<typename T, typename A>
T* PointerOf(std::vector<T,A> & vec)
{
return &vec.at(0);
}
template<typename T, typename A>
const T* ConstPointerOf(const std::vector<T,A> & vec)
{
return &vec.at(0);
}
myfun(ConstPointerOf(mdata[s][i]));
Edit: I added the template parameter for the vector allocator as suggested in the comments; I also used at() instead of [] so I wouldn't have to check for an empty vector, and I added a second version of the function for a const pointer.
I think
&(*mdata[s][i].begin());
is returning a std:vector of type double.
So, the following seems to work for me:
#include <vector>
void fun(const double data[])
{
}
int main()
{
std::vector<std::vector<std::vector<double> > > data3d;
....
fun(&(data3d[0][0].front()));
}