Перенос элементов из одного forward_list в другой в зависимости от условия

У меня есть два forward_lists: list1 а также list2, Я хотел бы перебрать первый и перенести элементы во второй на основе условия. Вот пример использования forward_list<int> это не работает, но я думаю, выражает то, что я хочу.

#include <iostream>
#include <forward_list>

using namespace std;

int main(void)
{
    forward_list<int> list1 = {1, 2, 3, 4, 5, 6};
    forward_list<int> list2;

    //Transfer elements between 2 and 5 from list1 to list2.    
    forward_list<int>::const_iterator iter_before = list1.before_begin();
    forward_list<int>::const_iterator iter = list1.begin();
    while ( iter != list1.end())
    {
        int item = *iter;
        cout << item ;
        if (2 <= item && item <= 5 )
        {
            list2.splice_after(list2.before_begin(),list1,iter_before);
            iter_before = iter;
            iter++;
            cout << "! "; // Indicates if current item is transferred.
        }
        else
        {
            iter++;
            iter_before++;
            cout << " ";
        }
    }

    cout << "\nList 1: ";
    for (auto item : list1)
    {
        cout << item << " ";
    }
    cout << "\nList 2: ";
    for (auto item : list2)
    {
        cout << item << " ";
    }
    cout << endl;

    return 0;
}

Я пытался сбросить iter а также iter_before итераторы к началу list1, который работает, но пересекает некоторые list1 элементы более одного раза (перезапускается). Я также пытался копировать элементы в list2 сначала, а затем стирая элемент на list1, который тоже работает. Я считаю оба эти решения неэффективными.

Кто-нибудь может предложить более эффективный, который включает в себя просто обмен указателями в списке?

2 ответа

Хитрость заключается в том, что:

  1. Вам нужно получить итератор для элемента, следующего за тем, который вы склеите в другой список - и это должно произойти до объединения. После сращивания этот итератор будет указывать на следующий элемент для обработки.
  2. После сращивания, iter_before все еще указывает прямо перед следующим обрабатываемым элементом - его менять не нужно.

Итак, в вашем ifвместо этого:

auto iter_next = std::next(iter);
list2.splice_after(list2.before_begin(),list1,iter_before);
iter = iter_next;

Демо

Ваш ответ точно описывает вариант использования STL copy_if ( http://www.cplusplus.com/reference/algorithm/copy_if/).

Другие вопросы по тегам