Iterating over a container bidirectionally

2019-07-12 15:32发布

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;
    }
}

3条回答
虎瘦雄心在
2楼-- · 2019-07-12 16:14

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;
}
查看更多
倾城 Initia
3楼-- · 2019-07-12 16:31

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. enter image description here

查看更多
走好不送
4楼-- · 2019-07-12 16:33

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());
    }
}
查看更多
登录 后发表回答