How to get random pointer form list of pointers ?
I have simple custom class Buildings and list
std::list<Buidldings*> temp;
size of temp is greater than zero. How to get random pointer from list ( 0 - temp.size)?
Use std::rand to pick an appropriate index and then advance an iterator:
assert( !temp.empty() );
std::list<Buidldings*>::const_iterator it = temp.begin();
std::advance( it, std::rand() % temp.size() );
Buidldings *p = *it;
Try this:
template<typename ContainerType >
typename ContainerType::iterator get_random(ContainerType & container)
{
ContainerType::iterator iter = container.begin();
std::advance(iter,rand() %container.size());
return iter ;
}
template<typename ContainerType >
typename ContainerType::const_iterator get_random(const ContainerType & container)
{
... (same as above)
}
From here
Related
I want to delete some map elements satisfying a condition. I did find a solution but I did not know how use it.
I have:
std::map<char,int> first;
first['a']=10;
first['b']=60;
first['c']=50;
first['d']=70;
the solution given is :
namespace stuff {
template< typename ContainerT, typename PredicateT >
void erase_if( ContainerT& items, const PredicateT& predicate ) {
for( auto it = items.begin(); it != items.end(); ) {
if( predicate(*it) ) it = items.erase(it);
else ++it;
}
};
}
What I need is how to adopt this function to delete elements having number <= 50:
using stuff::erase_if;
int test_value = 50; // or use whatever appropriate type and value
erase_if(container, [&test_value]( item_type& item ) {
return item.property <= test_value; // or whatever appropriate test
});
Why not use std::map::erase? As in
first.erase(first.begin());
That will remove the "first" item from the map.
If you want to remove a specific key, then it's just the same:
first.erase('a');
Your issue here is with your lambda in
erase_if(container, [&test_value]( item_type& item ) {
return item.property <= test_value; // or whatever appropriate test
});
You have item_type& item and item.property which is not what you want. When you dereference a map iterator you get a std::pair<const key_type, T> and that is what the lambda needs to take. We could use
erase_if(container, [&test_value]( const std::map<char,int>::value_type& item ) {
return item.second <= test_value;
});
But this means if we change the map to use some other key we need to change the type of item. To avoid that we can use a generic lambda using auto like
erase_if(container, [&test_value]( const auto& item ) {
return item.second <= test_value;
});
I want to define v to be the same type as an element pointed at by RAIterator below.
template < class RAIterator , class Comparator >
void g_quick_sort_3w_opt (RAIterator beg, RAIterator end, Comparator& cmp)
{
if ((end-beg) < 2)
return;
RAIterator low = beg;
RAIterator hih = end;
RAIterator i = beg;
T v = *beg; //I want T to be the type of an element pointed at by RAIterator
while (!(i == hih))
{
if (cmp(*i , v)) Swap(*low++, *i++);
else if (*i == v) ++i;
else Swap(*i, *--hih);
}
g_quick_sort_3w_opt(beg, low, cmp);
g_quick_sort_3w_opt(hih, end, cmp);
}
Swap is the one from genalg.h
right now my test input is a list of integers, the above works if I use int instead of T.
Take a look at std::iterator_traits, especially the reference and value_type members.
typename std::iterator_traits<RAIterator>::value_type v = ...;
typename std::iterator_traits<RAIterator>::reference v = ...;
Of course, you might be well-served with just using automatic type-deduction:
auto v = ...; // Beware of proxies
typename RAIterator::value_type v = *beg;
With C++11, you can use auto
auto v = *beg;
I have a container<std::deque<T>> and a const T*ptr which I know points to an object in one of the contained deques. Now, I like to know (1) which deque it comes from and (2) its index in that one. How to get that info?
I'm aware that I can iterate over all objects, but there ought to be a faster solution, ought it not?
Something like (and I havent compiled this but you get the idea):
container<deque<T>> MyCont;
for( auto iter = MyCont.begin(); iter != MyCont.end(); ++iter )
{
auto foundIter = find( *iter.begin(), *iter.end(), MyObject );
if ( foundIter != *iter.end() )
{
dequeIndex = distance( *iter.begin(), foundIter );
containerIndex = distance( MyCont.begin(), iter );
break;
}
}
That's a task for a double iteration:
iterate over container
iterate over current element (a deque) and compare
#
template<typename container> std::pair<container::iterator_t, size_t> FindIndices(const container& c, const container::value_type* x) {
for(auto a = c.begin(); a != c.end(); a++)
for(auto b = a->begin(); b != a->end(); b++)
if(&*b == x)
return std::pair<container::iterator_t, size_t>(a, b-a->begin());
return std::pair<container::iterator_t, size_t>(c.end(), -1);
}
If you can instead store shared_pointers or unique_pointers in your container, you can use a std::map to efficiently retrieve the indices, as long as those don't change.
If only the queue does not change, then there is still some potential for savings.
I've a std::vector<int> and I need to remove all elements at given indexes (the vector usually has high dimensionality). I would like to know, which is the most efficient way to do such an operation having in mind that the order of the original vector should be preserved.
Although, I found related posts on this issue, some of them needed to remove one single element or multiple elements where the remove-erase idiom seemed to be a good solution.
In my case, however, I need to delete multiple elements and since I'm using indexes instead of direct values, the remove-erase idiom can't be applied, right?
My code is given below and I would like to know if it's possible to do better than that in terms of efficiency?
bool find_element(const vector<int> & vMyVect, int nElem){
return (std::find(vMyVect.begin(), vMyVect.end(), nElem)!=vMyVect.end()) ? true : false;
}
void remove_elements(){
srand ( time(NULL) );
int nSize = 20;
std::vector<int> vMyValues;
for(int i = 0; i < nSize; ++i){
vMyValues.push_back(i);
}
int nRandIdx;
std::vector<int> vMyIndexes;
for(int i = 0; i < 6; ++i){
nRandIdx = rand() % nSize;
vMyIndexes.push_back(nRandIdx);
}
std::vector<int> vMyResult;
for(int i=0; i < (int)vMyValues.size(); i++){
if(!find_element(vMyIndexes,i)){
vMyResult.push_back(vMyValues[i]);
}
}
}
I think it could be more efficient, if you just just sort your indices and then delete those elements from your vector from the highest to the lowest. Deleting the highest index on a list will not invalidate the lower indices you want to delete, because only the elements higher than the deleted ones change their index.
If it is really more efficient will depend on how fast the sorting is. One more pro about this solultion is, that you don't need a copy of your value vector, you can work directly on the original vector. code should look something like this:
... fill up the vectors ...
sort (vMyIndexes.begin(), vMyIndexes.end());
for(int i=vMyIndexes.size() - 1; i >= 0; i--){
vMyValues.erase(vMyValues.begin() + vMyIndexes[i])
}
to avoid moving the same elements many times, we can move them by ranges between deleted indexes
// fill vMyIndexes, take care about duplicated values
vMyIndexes.push_back(-1); // to handle range from 0 to the first index to remove
vMyIndexes.push_back(vMyValues.size()); // to handle range from the last index to remove and to the end of values
std::sort(vMyIndexes.begin(), vMyIndexes.end());
std::vector<int>::iterator last = vMyValues.begin();
for (size_t i = 1; i != vMyIndexes.size(); ++i) {
size_t range_begin = vMyIndexes[i - 1] + 1;
size_t range_end = vMyIndexes[i];
std::copy(vMyValues.begin() + range_begin, vMyValues.begin() + range_end, last);
last += range_end - range_begin;
}
vMyValues.erase(last, vMyValues.end());
P.S. fixed a bug, thanks to Steve Jessop that patiently tried to show me it
Erase-remove multiple elements at given indices
Update: after the feedback on performance from #kory, I've modified the algorithm not to use flagging and move/copy elements in chunks (not one-by-one).
Notes:
indices need to be sorted and unique
uses std::move (replace with std::copy for c++98):
Github
Live example
Code:
template <class ForwardIt, class SortUniqIndsFwdIt>
inline ForwardIt remove_at(
ForwardIt first,
ForwardIt last,
SortUniqIndsFwdIt ii_first,
SortUniqIndsFwdIt ii_last)
{
if(ii_first == ii_last) // no indices-to-remove are given
return last;
typedef typename std::iterator_traits<ForwardIt>::difference_type diff_t;
typedef typename std::iterator_traits<SortUniqIndsFwdIt>::value_type ind_t;
ForwardIt destination = first + static_cast<diff_t>(*ii_first);
while(ii_first != ii_last)
{
// advance to an index after a chunk of elements-to-keep
for(ind_t cur = *ii_first++; ii_first != ii_last; ++ii_first)
{
const ind_t nxt = *ii_first;
if(nxt - cur > 1)
break;
cur = nxt;
}
// move the chunk of elements-to-keep to new destination
const ForwardIt source_first =
first + static_cast<diff_t>(*(ii_first - 1)) + 1;
const ForwardIt source_last =
ii_first != ii_last ? first + static_cast<diff_t>(*ii_first) : last;
std::move(source_first, source_last, destination);
// std::copy(source_first, source_last, destination) // c++98 version
destination += source_last - source_first;
}
return destination;
}
Usage example:
std::vector<int> v = /*...*/; // vector to remove elements from
std::vector<int> ii = /*...*/; // indices of elements to be removed
// prepare indices
std::sort(ii.begin(), ii.end());
ii.erase(std::unique(ii.begin(), ii.end()), ii.end());
// remove elements at indices
v.erase(remove_at(v.begin(), v.end(), ii.begin(), ii.end()), v.end());
What you can do is split the vector (actually any non-associative container) in two
groups, one corresponding to the indices to be erased and one containing the rest.
template<typename Cont, typename It>
auto ToggleIndices(Cont &cont, It beg, It end) -> decltype(std::end(cont))
{
int helpIndx(0);
return std::stable_partition(std::begin(cont), std::end(cont),
[&](typename Cont::value_type const& val) -> bool {
return std::find(beg, end, helpIndx++) != end;
});
}
you can then delete from (or up to) the split point to erase (keep only)
the elements corresponding to the indices
std::vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
int ar[] = { 2, 0, 4 };
v.erase(ToggleIndices(v, std::begin(ar), std::end(ar)), v.end());
If the 'keep only by index' operation is not needed you can use remove_if insted of stable_partition (O(n) vs O(nlogn) complexity)
To work for C arrays as containers the lambda function should be
[&](decltype(*(std::begin(cont))) const& val) -> bool
{ return std::find(beg, end, helpIndx++) != end; }
but then the .erase() method is no longer an option
If you want to ensure that every element is only moved once, you can simply iterate through each element, copy those that are to remain into a new, second container, do not copy the ones you wish to remove, and then delete the old container and replace it with the new one :)
This is an algorithm based on Andriy Tylychko's answer so that this can make it easier and faster to use the answer, without having to pick it apart. It also removes the need to have -1 at the beginning of the indices list and a number of items at the end. Also some debugging code to make sure the indices are valid (sorted and valid index into items).
template <typename Items_it, typename Indices_it>
auto remove_indices(
Items_it items_begin, Items_it items_end
, Indices_it indices_begin, Indices_it indices_end
)
{
static_assert(
std::is_same_v<std::random_access_iterator_tag
, typename std::iterator_traits<Items_it>::iterator_category>
, "Can't remove items this way unless Items_it is a random access iterator");
size_t indices_size = std::distance(indices_begin, indices_end);
size_t items_size = std::distance(items_begin, items_end);
if (indices_size == 0) {
// Nothing to erase
return items_end;
}
// Debug check to see if the indices are already sorted and are less than
// size of items.
assert(indices_begin[0] < items_size);
assert(std::is_sorted(indices_begin, indices_end));
auto last = items_begin;
auto shift = [&last, &items_begin](size_t range_begin, size_t range_end) {
std::copy(items_begin + range_begin, items_begin + range_end, last);
last += range_end - range_begin;
};
size_t last_index = -1;
for (size_t i = 0; i != indices_size; ++i) {
shift(last_index + 1, indices_begin[i]);
last_index = indices_begin[i];
}
shift(last_index + 1, items_size);
return last;
}
Here is an example of usage:
template <typename T>
std::ostream& operator<<(std::ostream& os, std::vector<T>& v)
{
for (auto i : v) {
os << i << " ";
}
os << std::endl;
return os;
}
int main()
{
using std::begin;
using std::end;
std::vector<int> items = { 1, 3, 6, 8, 13, 17 };
std::vector<int> indices = { 0, 1, 2, 3, 4 };
std::cout << items;
items.erase(
remove_indices(begin(items), end(items), begin(indices), end(indices))
, std::end(items)
);
std::cout << items;
return 0;
}
Output:
1 3 6 8 13 17
17
The headers required are:
#include <iterator>
#include <vector>
#include <iostream> // only needed for output
#include <cassert>
#include <type_traits>
And a Demo can be found on godbolt.org.
I am storing values in a std::map
I am finding two values in the map, and I want to iterate between the first through to the last item - however the <= operator is not implemented, so I can't do somethimng like this:
void foobar(const DatedRecordset& recs, const double startstamp, const double endtstamp)
{
DatedRecordsetConstIter start_iter = recs.lower_bound(startstamp), end_iter = recs.lower_bound(endtstamp);
// Can't do this .... (<= not defined)
//for (DatedRecordsetConstIter cit = start_iter; cit <= end_iter; cit++ )
/ So have to resort to a hack like this:
for (DatedRecordsetConstIter cit = start_iter; cit != recs.end(); cit++ ) {
if ((*cit).first <= (*end_iter).first){
//do something;
}
else
break;
}
}
}
Is there a more elegant way of iterating between two known iterators?
Use != instead of <= and it will do what you want it to do.
void foobar(const DatedRecordset& recs, const double startstamp, const double endtstamp)
{
DatedRecordsetConstIter start_iter = recs.lower_bound(startstamp),
end_iter = recs.upper_bound(endtstamp);
for (DatedRecordsetConstIter cit = start_iter; cit != end_iter; ++cit) {
}
}
There isn't a <= operator for std::map<>::iterator, but using != on end_iter should do basically the same thing. If you want to include the end iterator itself in the iteration, use something like a do loop to do the != test at the end.
struct ManipulateMatchingPairs {
template<class K, class V>
void operator()(const std::pair<K,V>& p) const {
// do with p.second as you please here.
}
};
// ...
std::for_each(start_iter, end_iter, ManipulateMatchingPairs());
You have to use the != operator. I believe this is because a std::map isn't necessarily contiguous in memory (so the <= operator wouldn't make much sense, whereas a std::vector would), I could be wrong though
The STL for_each algorithm also will not include the ending iterator in the loop. You could always increcment end_iter and just use for_each so that it will be included, though.
void foobar(const DatedRecordset& recs,
const double startstamp,
const double endtstamp)
{
DatedRecordsetConstIter start_iter = recs.lower_bound(startstamp);
DatedRecordsetConstIter end_iter = recs.lower_bound(endtstamp);
if(end_iter != recs.end())
++end_iter;
for_each(start_iter, end_iter, []()
{
//do something inside the lambda.
});
}
Something like that maybe? I didn't give it a compile check ...
If you want to include the end iterator in the loop, you can increment your end-condition iterator ++end_iter. After that the loop with cit != end_iter does the same as you intend to do with cit <= end_iter before incrementing.