5

次の動作で 2 つのマップを一緒に追加したいと考えています。

キーが存在する場合 -> 2 つのキー値を一緒に追加します。

キーが存在しない場合 -> ペアを挿入してマップします。

標準ライブラリのアルゴリズムをいくつか見てきました。つまり、変換しますが、私が望むことをしていないようです。

このリンクから取得

template < class InputIterator, class OutputIterator, class UnaryOperator >
  OutputIterator transform ( InputIterator first1, InputIterator last1,
                             OutputIterator result, UnaryOperator op )
{
  while (first1 != last1)
    *result++ = op(*first1++);  // or: *result++=binary_op(*first1++,*first2++);
  return result;
}

ここからの私の考えは、使用時に2番目のマップからイテレータが1つしかないことと、適切なファンクタ

 *result++=binary_op(*first1++,*first2++);

したがって、キー値を見つけるために 2 番目のマップをループすることはできません。

1つの考えは、微妙な変更を加えて独自のアルゴリズムを作成することだけでした.

template < class InputIterator, class ContainerType, class BinaryOperator >
  void myTransform ( InputIterator first1, InputIterator last1,
                               ContainerType cont2,  
                               BinaryOperator binary_op )
{
  while (first1 != last1)
    binary_op(first1++, cont2); //cont2 passed by reference 
}

その後、次を使用できます。

cont2.find()ファンクターでマップ全体を検索します。

これは私が考えていたことのより完全な例ですが、解決できないコンパイルエラーが発生したようです(BinaryOperatorタイプを推測しているようです...以下を参照)?

#include <map>
#include <string>
#include <iostream>

template < class InputIterator, class ContainerType, class BinaryOperator >
void myTransform ( InputIterator first1, InputIterator last1,
                 ContainerType &cont2, 
                 BinaryOperator binary_op )
{
  while (first1 != last1)
    binary_op(first1++, cont2); //cont2 passed by reference
}

template<class IteratorType, class ContainerType>
struct AddMapValues:
  std::binary_function<IteratorType, ContainerType, void>
{
  void operator()(IteratorType itr, ContainerType& cont)
  {
    if( cont.find(itr->first) != cont.end() ) cont[itr->first] = cont.find(itr->first).second + itr->second;
    else cont.insert( (*itr) );
  }
};


int main()
{
  typedef std::map<std::string, double> stringDoubleMap;
  typedef std::map<std::string, double>::iterator stringDoubleMapItr;
  typedef void (*ptrfnt)(stringDoubleMapItr, stringDoubleMap& );

  stringDoubleMap map1;
  stringDoubleMap map2;

  map1.insert( stringDoubleMap::value_type("Test1",1.0) );
  map1.insert( stringDoubleMap::value_type("Test2",2.0) );
  map1.insert( stringDoubleMap::value_type("Test3",3.0) );

  map2.insert( stringDoubleMap::value_type("Test1",1.0) );
  map2.insert( stringDoubleMap::value_type("Test2",2.0) );
  map2.insert( stringDoubleMap::value_type("Test3",3.0) );

  myTransform( map1.begin(), map1.end(),
               map2, 
               AddMapValues< stringDoubleMapItr, stringDoubleMap >() );

  return 0;

}

ここに私のコンパイラエラーがあります:

testingMapTransforms.cxx: In function ‘int main()’:

testingMapTransforms.cxx:52:85: error: no matching function for call to     ‘myTransform(std::map<std::basic_string<char>, double>::iterator, std::map<std::basic_string<char>, double>::iterator, stringDoubleMap&, std::map<std::basic_string<char>, double>::iterator, AddMapValues<std::_Rb_tree_iterator<std::pair<const std::basic_string<char>, double> >, std::map<std::basic_string<char>, double> >)’

testingMapTransforms.cxx:52:85: note: candidate is:

testingMapTransforms.cxx:12:20: note: template<class InputIterator, class ContainerType, class   OutputIterator, class BinaryOperator> OutputIterator myTransform(InputIterator, InputIterator,  ContainerType, OutputIterator, BinaryOperator)

別のイテレータがどこかから来ているようで、コンテナの型が正しく読み取られていませんか?

何か案は?

私は使っている

gcc - GNU プロジェクトの C および C++ コンパイラ

Ubuntu/リナロ 4.6.3-1ubuntu5

ありがとう

ノート:

回答で上記のコードの動作バージョンを更新しました。代わりに質問コードを変更する必要があると思われる場合は、お知らせください。ベストプラクティスがわからない

4

4 に答える 4

12
I want to add two maps together with the following behavior:
If key exists add two key values together.
If key does not exist. Insert pair to map.

単純なforループで、必要なことができると思います。

for(auto it = map2.begin(); it != map2.end(); ++it) map1[it->first] += it->second;

キーが存在する場合、値は既存のキーに追加されます。キーが存在しない場合は、キーoperator[]を挿入し、その値はデフォルトで初期化されます(の場合は0.0 double)。

ここでは、どのコンテナでも機能するジェネリック関数を使用するのは賢明ではないと思います。たとえば、vectorとmapのinsert()とoperator[]のセマンティクスはあまりにも異なります。

于 2012-06-13T11:21:10.167 に答える
2

コードが読み取れません。エラーが発生しやすいです。

手作業で行いますが、一度に1つのことを行います。増分ポインター、それらの逆参照、マップへの要素の追加、および別のポインターからのクエリをすべて同じ行に混在させないでください。それは混乱してしまいます。

于 2012-06-13T11:14:44.197 に答える
2

でできるとは思いませんtransform。2つのコンテナがあり、2つのイテレータペアが必要です。要素がそのうちの1つだけにある場合は、それらを別々に進める必要があります。の2つのシーケンスバージョンはtransform、ロックステップでそれらを進めます。

手で行うのはそれほど難しいことではありません。次のようなもの、おそらく:

typedef std::map<std::string, std::double> Map

Map
addValues( Map const& m1, Map const& m2 )
{
    Map results;
    Map::const_iterator i1 = m1.begin();
    Map::const_iterator i2 = m2.begin();
    while ( i1 != m1.end() && i2 != m2.end() ) {
        if ( i1->first < i2->first ) {
            results.insert( results.end(), *i1 );
            ++ i1;
        } else if ( i2->first < i1->first ) {
            results.insert( results.end(), *i2 );
            ++ i2;
        } else {
            results.insert( results.end(),
                            Map::value_type( i1->first, i1->second + i2->second ) );
            ++ i1;
            ++ i2;
        }
    }
    results.insert( i1, m1.end() );
    results.insert( i2, m2.end() );
    return results;
}

(テンプレートにする前に、まずこのように機能させます。)

于 2012-06-13T11:25:08.400 に答える
0

上記の改訂版はこちらです。質問コードには多くのバグがありましたが、これは機能しているようで、同じ考えです:

template < class InputIterator, class ContainerType, class BinaryOperator >
void myTransform ( InputIterator first1, InputIterator last1, ContainerType &cont2, BinaryOperator binary_op )
{
  while (first1 != last1)
    (*binary_op)(first1++, cont2); //cont2 passed by reference
}

template<class IteratorType, class ContainerType>
struct AddMapValues:
  std::binary_function<IteratorType, ContainerType, void>
{
  static void Add(IteratorType itr, ContainerType& cont)
  {
    cont[itr->first] += itr->second;
  }
};

int main()
{

  typedef std::map<std::string, double> stringDoubleMap;
  typedef std::map<std::string, double>::iterator stringDoubleMapItr;
  typedef void (*ptrfnt)(stringDoubleMapItr, stringDoubleMap& );

  stringDoubleMap map1;
  stringDoubleMap map2;

  map1.insert( stringDoubleMap::value_type("Test1",1.0) );
  map1.insert( stringDoubleMap::value_type("Test2",2.0) );
  map1.insert( stringDoubleMap::value_type("Test4",3.0) );

  map2.insert( stringDoubleMap::value_type("Test1",1.0) );
  map2.insert( stringDoubleMap::value_type("Test2",10.0) );
  map2.insert( stringDoubleMap::value_type("Test3",3.0) );

  myTransform( map1.begin(), map1.end(), map2, AddMapValues<stringDoubleMapItr, stringDoubleMap >::Add );

  for(stringDoubleMapItr itr = map2.begin(); itr != map2.end(); ++itr ){
    std::cout << "INFO: Key: " << itr->first << " | Value: " << itr->second  << std::endl;
  }

  return 0;

}
于 2012-06-13T13:29:51.343 に答える