Перебор парных элементов в контейнере пар (C ++) - PullRequest
4 голосов
/ 30 ноября 2009

Если у меня есть контейнер (vector, list и т. Д.), Где каждый элемент представляет собой std::pair, существует ли простой способ перебора каждого элемента каждой пары?

т.е.

std::vector<std::pair<int,int> > a;
a.push_back(std::pair(1,3));
a.push_back(std::pair(2,3));
a.push_back(std::pair(4,2));
a.push_back(std::pair(5,2));
a.push_back(std::pair(1,5));

и затем возможность перебирать значение: 1,3,2,3,4,2,5,2,1,5?

Аналогично, какой тип функтора / функции вернул бы мне контейнер (того же типа) с плоским списком парных элементов, как указано выше?

Ответы [ 6 ]

7 голосов
/ 30 ноября 2009

Для начала вы должны создать свой собственный класс итератора, который соединяет флаг, обозначающий позицию внутри пары, с итератором container<pair>

.

Во-вторых, это проще, хотя, чтобы быть настолько общим, насколько вы хотите (контейнер того же типа), вам нужен шаблон typedef . Вот только для вектора:

template <class V>
std::vector<V> flatten_pairs(std::vector<std::pair<V,V> > const& a) {
  typedef std::vector<std::pair<V,V> > A;
  std::vector<V> ret;
  for (typename A::const_iterator i=a.begin(),e=a.end();i!=e;++i) {
    ret.push_back(i->first);
    ret.push_back(i->second);
  }
  return ret;
}

Вот как вы подделываете шаблон typedef:

template <class C>
struct same_container;

template <class V>
struct same_container<std::vector<V> > {
  template <class W> struct rebind { typedef std::vector<W> type; };
};

template <class V>
struct same_list<std::list<V> > {
  template <class W> struct rebind { typedef std::list<W> type; };
};

template <class C>
typename same_container<C>::rebind<typename C::value_type::first_type>::type
flatten_pairs(C const& a);
5 голосов
/ 30 ноября 2009

Следующий код распечатает все значения по мере необходимости:

for ( size_t x = 0; x < a.size(); ++x ) {
    cout << a[x].first << "," << a[x].second << ",";
}

Я бы предпочел этот простой способ, чем создание собственного итератора.

3 голосов
/ 30 ноября 2009

Чтобы объединить ваш контейнер пар во второй контейнер, вы также можете просто написать свой собственный инсертор:

template<class C>
struct Inserter {
    std::back_insert_iterator<C> in;
    Inserter(C& c) : in(c) {}
    void operator()(const std::pair<typename C::value_type, typename C::value_type>& p)
    {
        *in++ = p.first;
    *in++ = p.second;
    }
};

template<class C>
Inserter<C> make_inserter(C& c)
{ 
    return Inserter<C>(c); 
}

// usage example:
std::list<int> l;
std::for_each(a.begin(), a.end(), make_inserter(l));
1 голос
/ 30 ноября 2009

Нет, на самом деле такого нет для std::pair. Возможно, вы захотите использовать вместо этого Boost Tuple. Кортеж немного похож на расширенную версию std::pair, которая допускает произвольное количество элементов (до некоторого предела, но обычно не менее 10) и дает доступ к элементам, например, к вектору / массиву (т.е. вы может получить доступ к элементам либо по имени, либо по индексу).

TR1 также включает в себя std :: tr1 :: tuple, который является подмножеством кортежа Boost, но если память служит, он все равно включает запрашиваемую вами функцию имени / индекса.

Редактировать: обратите внимание, что в обоих случаях нотации индекса требуется постоянная времени компиляции для индекса, поэтому вы не можете написать цикл (времени выполнения) для перебора элементов в кортеж - но вы можете сделать работу с небольшим количеством метапрограммирования. Boost Fusion включает в себя немало для поддержки того, что вам нужно (по странному совпадению, кортеж является частью библиотеки Fusion).

1 голос
/ 30 ноября 2009

Не существует простого способа выполнения итерации, которую вы хотите, но вы можете взглянуть на библиотеку boost :: iterator_adaptor или реализовать свой собственный итератор для этого (он не должен быть слишком сложным). Затем, по второму вопросу, вы можете использовать std :: copy с вашим новым адаптером итератора.

0 голосов
/ 30 ноября 2009

В какой-то момент вам нужно использовать first и second , даже если вы создаете свой собственный класс итератора. Я не думаю, что есть выход из этого (по крайней мере, портативным способом).

...