Iterating over a container bidirectionally

て烟熏妆下的殇ゞ 提交于 2019-12-11 00:55:17

问题


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

回答1:


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



回答2:


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.




回答3:


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


来源:https://stackoverflow.com/questions/51773078/iterating-over-a-container-bidirectionally

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!