簡體   English   中英

unique_copy元素值從map到vector

[英]unique_copy elements value from map to vector

我有一個map<K, V> ,我想使用unique_copy將值放入vector<V> 我試過這個,但它不起作用:

#include <iostream>
#include <map>
#include <algorithm>
#include <vector>
#include <functional>
using namespace std;
using namespace placeholders;


int main() {
    map<std::string, int> mp;

    mp["1"] = 1;
    mp["2"] = 2;
    mp["3"] = 3;
    mp["4"] = 3;
    mp["5"] = 3;
    mp["6"] = 4;
    mp["7"] = 2;

    vector<int> vec;

    unique_copy( mp.begin(), mp.end(),
                 back_inserter(vec),
                 bind(&map<std::string, int>::value_type::second, _1) );


    for( auto& i : vec )
        cout<< i <<" ";
}

預期產量:1 2 3 4 2

所有谷歌搜索都返回使用transform方法,但我需要unique_copy 有沒有辦法讓這項工作?

沒有辦法直接執行此操作,因為map迭代器的值類型和向量迭代器不兼容。 你真的需要某種變換,或迭代器適配器。

你可以使用boost::transform_iterator

auto getValue = [](const std::map<std::string, int>::value_type &pair) { return pair.second; };

unique_copy(
  boost::make_transform_iterator(mp.begin(), getValue),
  boost::make_transform_iterator(mp.end(), getValue),
  back_inserter(vec)
);

如果你不能使用Boost,你必須自己編寫這樣一個迭代器適配器:

template <class T_PairIterator>
struct SecondIterator
{
  typedef T_PairIterator PairIterator;
  typedef typename std::iterator_traits<PairIterator>::iterator_category iterator_category;
  typedef typename std::iterator_traits<PairIterator>::value_type::second_type value_type;
  typedef typename std::iterator_traits<PairIterator>::difference_type difference_type;
  typedef value_type *pointer;
  typedef value_type &reference;

  PairIterator it;

  SecondIterator() {}

  explicit SecondIterator(PairIterator it) : it(it) {}

  pointer operator-> () const { return &it->second; }

  reference operator* () const { return it->second; }

  SecondIterator& operator++ () { ++it; return *this; }

  SecondIterator operator++ (int) { SecondIterator ret(*this); ++it; return ret; }
};

template <class T>
bool operator== (const SecondIterator<T> &lhs, const SecondIterator<T> &rhs)
{ return lhs.it == rhs.it; }

template <class T>
bool operator!= (const SecondIterator<T> &lhs, const SecondIterator<T> &rhs)
{ return !(lhs == rhs); }

template <class T>
SecondIterator<T> makeSecondIterator(const T &it)
{ return SecondIterator<T>(it); }

然后你可以像這樣使用它:

unique_copy(
  makeSecondIterator(mp.begin()),
  makeSecondIterator(mp.end()),
  back_inserter(vec)
);

當然,可以使適配器更通用(也可以first使用),和/或更多封裝( it不需要公開); 它還需要對常量函數進行適當的處​​理。 但上面應該足以讓你有這個想法。

正如Vijay在他的評論中所說,你可以使用std::set而不是vector(如果你不需要向量的各個特征,當然,如連續存儲,自定義排序或隨機訪問)。 在這種情況下, std::set::insert將已經處理刪除重復項,您可以按照您嘗試的方式使用std::transform

std::set<int> set;
std::transform( mp.begin(), mp.end(), std::inserter(set),
                bind(&std::map<std::string, int>::value_type::second, _1) );

至於你修改過的問題

std :: set不會插入值,如果它已經在集合中但我不想連續重復。

好吧,在這種情況下,只需在向量中執行正常的復制(即std::transform ),然后執行std::unique ,這將刪除所有連續的重復項:

std::transform( mp.begin(), mp.end(), std::inserter(vec),
                bind(&std::map<std::string, int>::value_type::second, _1) );
vec.erase( std::unique(vec.begin(), vec.end()), vec.end() );

std::copy后跟vec.erase( std::unique( vec.begin(), vec.end() ), vec.end() ); 將與unique_copy結束在同一個地方並進行轉換。 它可能在中間使用額外的內存(在刪除冗余條目之前),但非常干凈。

手動副本是另一種選擇:

if(!src.empty()){
  auto* prev = &src.begin()->second;
  dest.push_back(*prev);
  for(auto it = std::next(src.begin()); it != sec.end(); ++it){
    if (it->second == *prev) continue;
    prev=&it->second;
    dest.push_back(*prev);
  }
}

注意thay prev在技​​術上是多余的(使用dest.back()而不是*prev除非在push_back ing時 - 使用->second )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM