5

how would one implement generic (aka works for multimap, sorted vector ...) equal range iterator? By this I mean it is an iterator that is a pair of iterators (begin and end of a particular equal_range)

Motivation for this is that I have a multimap that is called sortedword2word , and I use it to detect anagrams in an array of strings. So I would like to have a way to iterate over each equal range easily (easily as in LOC/readability way - I know I can easily do it by manually checking for .end() and if next is the same as current...)

If boost has implemented functionality like this that is acceptable A also.

8
  • 1
    Do you really need that? Using lower_bound/upper_bound you can get an iterator to the beginning of the range. Then just iterate while(*current == *next)... Commented Jun 27, 2013 at 9:45
  • @jrok " So I would like to have a way to iterate over each equal range easily(easily as in LOC way I know I can easily do it by manually checking for .end() and if next is the same as current...)" Commented Jun 27, 2013 at 9:49
  • I missed that part, sorry. Well, how much boilerplate can you handle to save 1 or 2 LOC? :) Commented Jun 27, 2013 at 9:51
  • 2
    @jrok it is not about that.. how much you save using std::swap instead of third tmp var? it is about readability... for (auto it = something.begin(), something.end() is much clearer than while ... if ... Ill update my answer Commented Jun 27, 2013 at 10:25
  • *my question ___________________ Commented Jun 27, 2013 at 11:52

3 Answers 3

5
+50

Maybe like this:

template <typename Iter> class eqrange
{
    Iter a, b, e;

    void adv()
    {
        e = a;
        while (e != b && *e == *a) { ++e; }
    }

public:

    eqrange(Iter x, y) : a(x), b(y) { adv(); }

    Iter begin() { return a; }
    Iter end()  { return e; }

    eqrange & operator++() { b = e; adv(); }

    bool operator==(eqrange const & rhs) const
    {
        return a == rhs.a && b == rhs.b && e == rhs.e;
    }

    eqrange make_end() const
    { 
        return eqrange(b, b);
    }
};

template <typename Iter>
eqrange<Iter> er(Iter b, Iter e)
{
    return eqrange<Iter>(b, e);
}

Usage:

auto r = er(v.begin(), v.end()), e = r.make_end();

while (r != e)
{
    for (auto x : r) { /* ... */ }
    ++r;
}
Sign up to request clarification or add additional context in comments.

Comments

2

Writing custom iterators can be a pain (if you're going to be rigorous in terms of meeting all the requirements of, say, the ForwardIterator concept).

Will the following suffice?

template <typename Range, typename Func>
void foreach_equal_range(Range& range, Func func)
{
    using std::begin;
    using std::end;
    foreach_equal_range(begin(range), end(range), func);
}

template <typename ForwardIt, typename Func>
void foreach_equal_range(ForwardIt begin, ForwardIt end, Func func)
{
     while (begin != end)
     {
         auto it = std::upper_bound(begin, end, *begin);
         func(begin, it);
         begin = it;
     }
}

Comments

1

i would do something like this (hopefully i understood the question in detail..) :

template<typename Container, typename Function>
void                  apply(Container& a, const Container& b, Function f)
{
  auto                aItr = a.begin();
  auto                bItr = b.begin();

  for (; aItr != a.end() && bItr != b.end(); ++aItr, ++bItr)
    f(*aItr, *bItr);
}

Assuming you can use C++11, but it is still easilly modifiable to match older C++ norms.

jav

5 Comments

lets say i have multimap that is a->1,a->2,a->3,b->4,b->3 ... I want to have iterate over equal_ranges(two of them in this case: from a->1 to a->3 and from b->4 to b-->3
So what you call range is a number of elements through wich you want to iterate, but which are not strictly corresponding to each-others index, is that right ?
@NoSenseEtAl: But then, why is it not appropriate std::equal_range?
when you do ++ on "equal range iterator" you get a new iterator that is begin and end of next equal range... aka ill use | to split equal ranges in example : (1,3) (1,4) | (2,3)| (3,10) (3,22)
so in this example iterator can have 3 values: (1,3)-(1,4) (2,3)-(2-3) (3,10)-(3,22) and maybe (range_end) - (range_end)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.