Is it possible to iterate a vector from the end to the beginning?
for (vector<my_class>::iterator i = my_vector.end();
i != my_vector.begin(); /* ?! */ ) {
}
Or is that only possible with something like that:
for (int i = my_vector.size() - 1; i >= 0; --i) {
}
One way is:
for (vector<my_class>::reverse_iterator i = my_vector.rbegin();
i != my_vector.rend(); ++i ) {
}
rbegin()/rend() were especially designed for that purpose. (And yes, incrementing a reverse_interator moves it backward.)
Now, in theory, your method (using begin()/end() & --i) would work, std::vector's iterator being bidirectional, but remember, end() isn't the last element — it's one beyond the last element, so you'd have to decrement first, and you are done when you reach begin() — but you still have to do your processing.
vector<my_class>::iterator i = my_vector.end();
while (i != my_vector.begin())
{
--i;
/*do stuff */
}
UPDATE: I was apparently too aggressive in re-writing the for() loop into a while() loop. (The important part is that the --i is at the beginning.)
If you have C++11 you can make use of auto.
for (auto it = my_vector.rbegin(); it != my_vector.rend(); ++it)
{
}
Starting with c++20, you can use a std::ranges::reverse_view and a range-based for-loop:
#include<ranges>
#include<vector>
#include<iostream>
using namespace std::ranges;
std::vector<int> const vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(auto& i : views::reverse(vec)) {
std::cout << i << ",";
}
Or even
for(auto& i : vec | views::reverse)
Unfortunately, at the time of writing (Jan 2020) no major compiler implements the ranges library, but you can resort to Eric Niebler's ranges-v3:
#include <iostream>
#include <vector>
#include "range/v3/all.hpp"
int main() {
using namespace ranges;
std::vector<int> const vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(auto& i : views::reverse(vec)) {
std::cout << i << ",";
}
return 0;
}
The well-established "pattern" for reverse-iterating through closed-open ranges looks as follows
// Iterate over [begin, end) range in reverse
for (iterator = end; iterator-- != begin; ) {
// Process `*iterator`
}
or, if you prefer,
// Iterate over [begin, end) range in reverse
for (iterator = end; iterator != begin; ) {
--iterator;
// Process `*iterator`
}
This pattern is useful, for example, for reverse-indexing an array using an unsigned index
int array[N];
...
// Iterate over [0, N) range in reverse
for (unsigned i = N; i-- != 0; ) {
array[i]; // <- process it
}
(People unfamiliar with this pattern often insist on using signed integer types for array indexing specifically because they incorrectly believe that unsigned types are somehow "unusable" for reverse indexing)
It can be used for iterating over an array using a "sliding pointer" technique
// Iterate over [array, array + N) range in reverse
for (int *p = array + N; p-- != array; ) {
*p; // <- process it
}
or it can be used for reverse-iteration over a vector using an ordinary (not reverse) iterator
for (vector<my_class>::iterator i = my_vector.end(); i-- != my_vector.begin(); ) {
*i; // <- process it
}
User rend() / rbegin() iterators:
for (vector<myclass>::reverse_iterator it = myvector.rbegin(); it != myvector.rend(); it++)
template<class It>
std::reverse_iterator<It> reversed( It it ) {
return std::reverse_iterator<It>(std::forward<It>(it));
}
Then:
for( auto rit = reversed(data.end()); rit != reversed(data.begin()); ++rit ) {
std::cout << *rit;
Alternatively in C++14 just do:
for( auto rit = std::rbegin(data); rit != std::rend(data); ++rit ) {
std::cout << *rit;
In C++03/11 most standard containers have a .rbegin() and .rend() method as well.
Finally, you can write the range adapter backwards as follows:
namespace adl_aux {
using std::begin; using std::end;
template<class C>
decltype( begin( std::declval<C>() ) ) adl_begin( C&& c ) {
return begin(std::forward<C>(c));
}
template<class C>
decltype( end( std::declval<C>() ) ) adl_end( C&& c ) {
return end(std::forward<C>(c));
}
}
template<class It>
struct simple_range {
It b_, e_;
simple_range():b_(),e_(){}
It begin() const { return b_; }
It end() const { return e_; }
simple_range( It b, It e ):b_(b), e_(e) {}
template<class OtherRange>
simple_range( OtherRange&& o ):
simple_range(adl_aux::adl_begin(o), adl_aux::adl_end(o))
{}
// explicit defaults:
simple_range( simple_range const& o ) = default;
simple_range( simple_range && o ) = default;
simple_range& operator=( simple_range const& o ) = default;
simple_range& operator=( simple_range && o ) = default;
};
template<class C>
simple_range< decltype( reversed( adl_aux::adl_begin( std::declval<C&>() ) ) ) >
backwards( C&& c ) {
return { reversed( adl_aux::adl_end(c) ), reversed( adl_aux::adl_begin(c) ) };
}
and now you can do this:
for (auto&& x : backwards(ctnr))
std::cout << x;
which I think is quite pretty.
Use reverse iterators and loop from rbegin() to rend()
I like the backwards iterator at the end of Yakk - Adam Nevraumont's answer, but it seemed complicated for what I needed, so I wrote this:
template <class T>
class backwards {
T& _obj;
public:
backwards(T &obj) : _obj(obj) {}
auto begin() {return _obj.rbegin();}
auto end() {return _obj.rend();}
};
I'm able to take a normal iterator like this:
for (auto &elem : vec) {
// ... my useful code
}
and change it to this to iterate in reverse:
for (auto &elem : backwards(vec)) {
// ... my useful code
}
If you can use The Boost Library, there is the Boost.Range that provides the reverse range adapter by including:
#include <boost/range/adaptor/reversed.hpp>
Then, in combination with a C++11's range-for loop, you can just write the following:
for (auto& elem: boost::adaptors::reverse(my_vector)) {
// ...
}
Since this code is briefer than the one using the iterator pair, it may be more readable and less prone to errors as there are fewer details to pay attention to.
Here's a super simple implementation that allows use of the for each construct and relies only on C++14 std library:
namespace Details {
// simple storage of a begin and end iterator
template<class T>
struct iterator_range
{
T beginning, ending;
iterator_range(T beginning, T ending) : beginning(beginning), ending(ending) {}
T begin() const { return beginning; }
T end() const { return ending; }
};
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// usage:
// for (auto e : backwards(collection))
template<class T>
auto backwards(T & collection)
{
using namespace std;
return Details::iterator_range(rbegin(collection), rend(collection));
}
This works with things that supply an rbegin() and rend(), as well as with static arrays.
std::vector<int> collection{ 5, 9, 15, 22 };
for (auto e : backwards(collection))
;
long values[] = { 3, 6, 9, 12 };
for (auto e : backwards(values))
;
can try this one (only for --i):
std:vector<int> vec = {1, 2, 3};
size_t i{ vec.size() - 1 };
while (i < size_t(-1))
{
auto& el = vec[i];
--i;
}
use this code
//print the vector element in reverse order by normal iterator.
cout <<"print the vector element in reverse order by normal iterator." <<endl;
vector<string>::iterator iter=vec.end();
--iter;
while (iter != vec.begin())
{
cout << *iter << " ";
--iter;
}
As I don't want to introduce alien-like new C++ syntax, and I simply want to build up on existing primitives, the below snippets seems to work:
#include <vector>
#include <iostream>
int main (int argc,char *argv[])
{
std::vector<int> arr{1,2,3,4,5};
std::vector<int>::iterator it;
// iterate forward
for (it = arr.begin(); it != arr.end(); it++) {
std::cout << *it << " ";
}
std::cout << "\n************\n";
if (arr.size() > 0) {
// iterate backward, simple Joe version
it = arr.end() - 1;
while (it != arr.begin()) {
std::cout << *it << " ";
it--;
}
std::cout << *it << " ";
}
// iterate backwards, the C++ way
std::vector<int>::reverse_iterator rit;
for (rit = arr.rbegin(); rit != arr.rend(); rit++) {
std::cout << *rit << " ";
}
return 0;
}
Related
I have a C++ vector of doubles, which is guaranteed to have an even number of elements. This vector stores the coordinates of a set of points as x, y coordinates:
A[2 * i ] is the x coordinate of the i'th point.
A[2 * i + 1] is the y coordinate of the i'th point.
How to implement an iterator that allows me to use STL style algorithms (one that takes an iterator range, where dereferencing an iterator gives back the pair of doubles corresponding to the x, y coordinates of the corresponding point) ?
I'm using C++17 if that helps.
We can use range-v3, with two adapters:
chunk(n) takes a range and adapts it into a range of non-overlapping ranges of size n
transform(f) takes a range of x and adapts it into a range of f(x)
Putting those together we can create an adaptor which takes a range and yields a range of non-overlapping pairs:
auto into_pairs = rv::chunk(2)
| rv::transform([](auto&& r){ return std::pair(r[0], r[1]); });
Using the r[0] syntax assumes that the input range is random-access, which in this case is fine since we know we want to use it on a vector, but it can also be generalized to work for forward-only ranges at the cost of a bit more syntax:
| rv::transform([](auto&& r){
auto it = ranges::begin(r);
auto next = ranges::next(it);
return std::pair(*it, *next);
})
Demo, using fmt for convenient printing:
int main() {
std::vector<int> v = {1, 1, 2, 2, 3, 3, 4, 4, 5, 5};
auto into_pairs = rv::chunk(2)
| rv::transform([](auto&& r){ return std::pair(r[0], r[1]); });
// prints {(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)}
fmt::print("{}\n", v | into_pairs);
}
It's unclear from the question if you wanted pair<T, T>s or pair<T&, T&>s. The latter is doable by providing explicit types to std::pair rather than relying on class template argument deduction.
C++ is a bit of a moving target - also when it comes to iterators (c++20 has concepts for that...). But would it not be nice to have a lazy solution to the problem. I.e. The tuples get generated on the fly, without casting (see other answers) and without having to write a loop to transform a vector<double> to a vector<tuple<double,double>>?
Now I feel I need a disclaimer because I am not sure this is entirely correct (language lawyers will hopefully point out, if I missed something). But it compiles and produces the expected output. That is something, yes?! Yes.
The idea is to build a pseudo container (which actually is just a facade to an underlying container) with an iterator of its own, producing the desired output type on the fly.
#include <vector>
#include <tuple>
#include <iostream>
#include <iterator>
template <class SourceIter>
struct PairWise {
PairWise() = delete;
PairWise(SourceIter first, SourceIter last)
: first{first}
, last{last}
{
}
using value_type =
typename std::tuple<
typename SourceIter::value_type,
typename SourceIter::value_type
>;
using source_iter = SourceIter;
struct IterState {
PairWise::source_iter first;
PairWise::source_iter last;
PairWise::source_iter current;
IterState(PairWise::source_iter first, PairWise::source_iter last)
: first{first}
, last{last}
, current{first}
{
}
friend bool operator==(const IterState& a, const IterState& b) {
// std::cout << "operator==(a,b)" << std::endl;
return (a.first == b.first)
&& (a.last == b.last)
&& (a.current == b.current);
}
IterState& operator++() {
// std::cout << "operator++()" << std::endl;
if (std::distance(current,last) >= 2) {
current++;
current++;
}
return *this;
}
const PairWise::value_type operator*() const {
// std::cout << "operator*()" << std::endl;
return std::make_tuple(*current, *(current+1));
}
};
using iterator = IterState;
using const_iterator = const IterState;
const_iterator cbegin() const {
return IterState{first,last};
}
const_iterator cend() const {
auto i = IterState{first,last};
i.current = last;
return i;
}
const_iterator begin() const {
// std::cout << "begin()" << std::endl;
return IterState{first,last};
}
const_iterator end() const {
// std::cout << "end()" << std::endl;
auto i = IterState{first,last};
i.current = last;
return i;
}
source_iter first;
source_iter last;
};
std::ostream& operator<<(std::ostream& os, const std::tuple<double,double>& value) {
auto [a,b] = value;
os << "<" << a << "," << b << ">";
return os;
}
template <class Container>
auto pairwise( const Container& container)
-> PairWise<typename Container::const_iterator>
{
return PairWise(container.cbegin(), container.cend());
}
int main( int argc, const char* argv[]) {
using VecF64_t = std::vector<double>;
VecF64_t data{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
for (const auto x : pairwise(data)) {
std::cout << x << std::endl;
}
return 0;
}
Elements in vector are stored in contiguous memory area, so you can use simple pointer arithmetics to access pair of doubles.
operator++ for iterator should skip 2 doubles at every use.
operator* can return tuple of references to double values, so you can read (pair = *it) or edit values (*it = pair).
struct Cont {
std::vector<double>& v;
Cont(std::vector<double>& v) : v(v) {}
struct Iterator : public std::iterator<std::input_iterator_tag , std::pair<double,double>> {
double* ptrData = nullptr;
Iterator(double* data) : ptrData(data) {}
Iterator& operator++() { ptrData += 2; return *this; }
Iterator operator++(int) { Iterator copy(*this); ptrData += 2; return copy; }
auto operator*() { return std::tie(*ptrData,*(ptrData+1)); }
bool operator!=(const Iterator& other) const { return ptrData != other.ptrData; }
};
auto begin() { return Iterator(v.data()); }
auto end() { return Iterator(v.data()+v.size());}
};
int main() {
std::vector<double> v;
v.resize(4);
Cont c(v);
for (auto it = c.begin(); it != c.end(); it++) {
*it = std::tuple<double,double>(20,30);
}
std::cout << v[0] << std::endl; // 20
std::cout << v[1] << std::endl; // 30
}
Demo
There's not an easy "C++" way to do this that's clean and avoids a copy of the original array. There's always this (make a copy):
vector<double> A; // your original list of points
vector<pair<double,double>> points;
for (size_t i = 0; i < A.size()/2; i+= 2)
{
points[i*2] = pair<double,double>(A[i], A[i+1]);
}
The following would likely work, violates a few standards, and the language lawyers will sue me in court for suggesting it. But if we can assume that the sizeof(XY) is the size of two doubles, has no padding, and expected alignment then cheating with a cast will likely work. This assumes you don't need a std::pair
Non standard stuff ahead
vector<double> A; // your original list of points
struct XY {
double x;
double y;
};
static_assert(sizeof(double)*2 == sizeof(XY));
static_assert(alignof(double) == alignof(XY));
XY* points = reinterpret_cast<XY*>(A.data());
size_t numPoints = A.size()/2;
// iterate
for (size_t i = 0; i < numPoints; i++) {
XY& point = points[i];
cout << point.x << "," << point.y << endl;
}
If you can guarantee that std::vector will always have an even number of entries, you could exploit the fact that an vector of doubles will have the same memory layout as a vector of pairs of doubles. This is kind of a dirty trick though so I wouldn't recommend it if you can avoid it. The good news is that the standard guarantees that vector elements will be contiguous.
inline const std::vector<std::pair<double, double>>& make_dbl_pair(std::vector<double>& v)
{
return reinterpret_cast<std::vector<std::pair<double, double>>&>(v);
}
This will only work for iteration with iterators. The size is likely to be double the number of pairs in the vector because it is still a vector of doubles underneath.
Example:
int main(int argc, char* argv[])
{
std::vector<double> dbl_vec = { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5 };
const std::vector<std::pair<double, double>>& pair_vec = make_dbl_pair(dbl_vec);
for (auto it = pair_vec.begin(); it != pair_vec.end(); ++it) {
std::cout << it->first << ", " << it->second << "\n";
}
std::cout << "Size: " << dbl_vec.size() << "\n";
return 0;
}
I'm trying to get the indices of one container where the elements match. Both containers are sorted in ascending order. Is there an algorithm or combo of algorithms that would place the indices of matching elements of sorted containers into another container?
I've coded an algorithm already, but was wondering if this has been coded before in the stl in some way that I didn't think of?
I would like the algorithm to have a running complexity comparable to the one I suggested, which I belive is O(min(m, n)).
#include <iterator>
#include <iostream>
template <typename It, typename Index_it>
void get_indices(It selected_it, It selected_it_end, It subitems_it, It subitems_it_end, Index_it indices_it)
{
auto reference_it = selected_it;
while (selected_it != selected_it_end && subitems_it != subitems_it_end) {
if (*selected_it == *subitems_it) {
*indices_it++ = std::distance(reference_it, selected_it);
++selected_it;
++subitems_it;
}
else if (*selected_it < *subitems_it) {
++selected_it;
}
else {
++subitems_it;
}
}
}
int main()
{
int items[] = { 1, 3, 6, 8, 13, 17 };
int subitems[] = { 3, 6, 17 };
int indices[std::size(subitems)] = {0};
auto selected_it = std::begin(items), it = std::begin(subitems);
auto indices_it = std::begin(indices);
get_indices(std::begin(items), std::end(items)
, std::begin(subitems), std::end(subitems)
, std::begin(indices));
for (auto i : indices) {
std::cout << i << ", ";
}
return 0;
}
We can use find_if to simplify the implementation of the function:
template<class SourceIt, class SelectIt, class IndexIt>
void get_indicies(SourceIt begin, SourceIt end, SelectIt sbegin, SelectIt send, IndexIt dest) {
auto scan = begin;
for(; sbegin != send; ++sbegin) {
auto&& key = *sbegin;
scan = std::find_if(scan, end, [&](auto&& obj) { return obj >= key; });
if(scan == end) break;
for(; scan != end && *scan == key; ++scan) {
*dest = std::distance(begin, scan);
++dest;
}
}
}
This doesn't make it that much shorter, but the code looks a little cleaner now. You're scanning until you find something as big as or equal to the key, and then you copy indicies to the destination as long as the source matches key.
maybe I misunderstodd the question. But there is a function in the algorithm library.
std::set_intersection
This does, what you want in one function. See:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
// Input values
std::vector<int> items{ 1,3,6,8,13,17 };
std::vector<int> subitems{ 3,6,17 };
// Result
std::vector<int> result;
// Do the work. One liner
std::set_intersection(items.begin(),items.end(), subitems.begin(),subitems.end(),std::back_inserter(result));
// Debug output: Show result
std::copy(result.begin(), result.end(), std::ostream_iterator<int>(std::cout, " "));
return 0;
}
If I misunderstood, then please tell me and I will find another solution.
EDIT:
I indeed misunderstood. You wanted the indices. Then maybe like this?
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using Iter = std::vector<int>::iterator;
int main()
{
// Input values
std::vector<int> items{ 1,3,6,8,13,17 };
std::vector<int> subitems{ 3,6,17 };
// Result
std::vector<int> indices{};
Iter it;
// Do the work.
std::for_each(subitems.begin(), subitems.end(), [&](int i) {it = find(items.begin(), items.end(), i); if (it != items.end()) indices.push_back(std::distance(items.begin(),it));});
// Debug output: Show result
std::copy(indices.begin(), indices.end(), std::ostream_iterator<int>(std::cout, " "));
return 0;
}
Unfortunately a very long "one-liner".
I need to think more . . .
The answer is yes but it will come with C++20:
you can use ranges for this purpose:
first make a view with some predicate you like:
auto result = items | ranges::view::filter(predicate);
then take the iterator to the original array from base, for example result.begin().base() will give you the iterator to the begin of result in the original array.
#include <algorithm>
#include <iostream>
#include <vector>
#include <iterator>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>
int main()
{
std::vector<int> items = { 1, 3, 6, 8, 13, 17 };
std::vector<int> subitems = { 3, 6, 17 };
auto predicate = [&](int& n){
for(auto& s : subitems)
if(n == s)
return true;
return false;
};
auto result = items | ranges::view::filter(predicate);
for (auto& n : result)
{
std::cout << n << '\n';
}
for(auto it = result.begin(); it != result.end(); ++it )
std::cout << it.base() - items.begin() << ' ';
}
see the godbolt
By using std::set_intersection, defining an assignment_iterator class and a assignment helper, this is possible:
#include <iterator>
#include <iostream>
#include <algorithm>
#include <vector>
template <typename Transform>
class assignment_iterator
{
Transform transform;
public:
using iterator_category = std::output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
assignment_iterator(Transform transform)
: transform(transform)
{}
// For some reason VC++ is assigning the iterator inside of std::copy().
// Not needed for other compilers.
#ifdef _MSC_VER
assignment_iterator& operator=(assignment_iterator const& copy)
{
transform.~Transform();
new (&transform) Transform(copy.transform);
return *this;
}
#endif
template <typename T>
constexpr assignment_iterator& operator=(T& value) {
transform(value);
return *this;
}
constexpr assignment_iterator& operator* ( ) { return *this; }
constexpr assignment_iterator& operator++( ) { return *this; }
constexpr assignment_iterator& operator++(int) { return *this; }
};
template <typename Transform>
assignment_iterator<Transform> assignment(Transform&& transform)
{
return { std::forward<Transform>(transform) };
}
int main()
{
int items[] = { 1, 3, 6, 8, 13, 17 };
int subitems[] = { 3, 6, 17 };
std::vector<int> indices;
std::set_intersection(std::begin(items), std::end(items)
, std::begin(subitems), std::end(subitems)
, assignment([&items, &indices](int& item) {
return indices.push_back(&item - &*std::begin(items));
})
);
std::copy(indices.begin(), indices.end()
, assignment([&indices](int& index) {
std::cout << index;
if (&index != &std::end(indices)[-1])
std::cout << ", ";
})
);
return 0;
}
Demo
It's more code, but maybe assignment is a more generic means to do other operations, that currently require a specific implementations like back_inserter and ostream_iterator, and thus be less code in the long run (e.g. like the other use above with std::copy)?
This should work properly all the time based on the documentation here:
elements will be copied from the first range to the destination range.
You can use std::find and std::distance to find the index of the match, then put it in the container.
#include <vector>
#include <algorithm>
int main ()
{
std::vector<int> v = {1,2,3,4,5,6,7};
std::vector<int> matchIndexes;
std::vector<int>::iterator match = std::find(v.begin(), v.end(), 5);
int index = std::distance(v.begin(), match);
matchIndexes.push_back(index);
return 0;
}
To match multiple elements, you can use std::search in similar fashion.
Is there a better way than the below code, to iterate over a container in either direction, using the same iterators?
#include <iostream>
#include <map>
int main()
{
const bool descend = false;
std::map<int, int> mapp;
mapp[1] = 1;
mapp[2] = 2;
mapp[3] = 3;
mapp[4] = 4;
std::map<int, int>::iterator startIter = descend ? --(mapp.end()) : mapp.begin();
std::map<int, int>::iterator endIter = descend ? --(mapp.begin()) : mapp.end();
while (startIter != endIter)
{
std::cout << startIter->first << std::endl;
descend ? --startIter : ++startIter;
}
}
Your code is invalid as this statement --(mapp.begin()) leads to UB. I would write a thin wrapper:
template<class Iter, class F>
void apply( Iter begin, Iter end, F f, bool forward )
{
while( begin != end )
f( forward ? *begin++ : *--end );
}
live example
or just simply rewrite your loop into:
auto begin = mapp.begin();
auto end = mapp.end();
while ( begin != end)
{
const auto &p = forward ? *begin++ : *--end;
std::cout << p.first << std::endl;
}
Is there a better way than the below code, to iterate over a container
in either direction, using the same iterators?
Yes. Use std::map::reverse_iterator. It will be a better way than the code you posted, but that will not be using the same iterators anymore, which was one of your requirements.
However, this will be less error-prone than the code you have written. In addition to that, you do not need to re-invent the wheel, if that is already in C++.
See output here
#include <iostream>
#include <map>
template<typename Iterator>
void print(const Iterator Begin, const Iterator End)
{
for(Iterator iter = Begin; iter != End; ++iter)
std::cout << iter->first << "\n";
}
int main()
{
const bool descend = true;
std::map<int, int> mapp;
mapp[1] = 1;
mapp[2] = 2;
mapp[3] = 3;
mapp[4] = 4;
descend ?
print(mapp.crbegin(), mapp.crend()):
print(mapp.cbegin(), mapp.cend());
return 0;
}
The image from cppreference.com will explain graphically, how does it work.
Write self-documenting code and it becomes simple. Break that loop out into its own function and call it with the appropriate iterators.
This is why we have "reverse iterators" they can be used to go backwards through a container by using the normal forward semantics.
#include <iostream>
#include <map>
template<typename I>
void printMapContainer(I begin, I end)
{
for (;begin != end; ++begin)
{
std::cout << begin->first << "\n";
}
}
int main()
{
const bool descend = false;
std::map<int, int> mapp;
mapp[1] = 1;
mapp[2] = 2;
mapp[3] = 3;
mapp[4] = 4;
if (descend) {
printMapContainer(mapp.rbegin(), mapp.rend());
}
else {
printMapContainer(mapp.begin(), mapp.end());
}
}
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;
}
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;
}
}