2012-04-13 10 views
2

私がのstd ::マップを持っている場合、同時にエレガントな方法がある:マップ内の要素を変更してその位置を取得する方法は?

  1. 挿入/そのキー
  2. が挿入された要素
へのイテレータを取得し、指定された要素を編集

マップに2ルックアップを行うことを妨げる私が見つけた最良の方法は次のとおりです。

std::map<int, int> myMap; 
//do some stuff with the map 
std::map<int,int>::iterator it = myMap.insert(std::pair<int, int>(0,0)).first; 
it->second = 0; //necessary because insert does not overwrite the values 

それは単一の文/行でそれらのものの両方を行うことは可能ですか? おかげ

+1

注意しかし、むしろ 'pair 'です。 –

+0

挿入したり編集したりします。どちらをお望みですか?明らかに、挿入用に1本のライナーがありますので、どういう疑問がありますか? –

+0

私はあなたが最も効率的な方法を見つけたと信じています。見た目が気に入らなければ、2つのステップを組み合わせた 'replace'関数を実装してください。でも、それはあなたの例の観点から実装されます。 – Chad

答えて

4

ああ、STLの関数とコンテナは、いつも期待しているとは限りません。あなただけの値ではなくペアをしたい場合は

template<class Map> 
inline typename Map::iterator ForceInsert1( 
    Map&       m, 
    const typename Map::key_type& k, 
    const typename Map::data_type& d) 
{ 
    typename Map::iterator it = m.insert( 
     typename Map::value_type(k, d)).first; 
    it->second = d; // only necessary if the key already exists 
    return it; 
} 

template<class Map> 
inline typename Map::iterator ForceInsert2( 
    Map&       m, 
    const typename Map::key_type& k, 
    const typename Map::data_type& d) 
{ 
    typename Map::iterator it = m.find(k); 
    if(it != m.end()) 
    { 
     it->second = d; 
    } 
    else 
    { 
     it = m.insert(typename Map::value_type(k, d)).first; 
    } 
    return it; 
} 

typedef std::map<int, int> MyMap; 
void Foo(MyMap& myMap) 
{ 
    ForceInsert1(myMap, 42, 100); 
    ForceInsert2(myMap, 64, 128); 
} 
+0

typenameのMap :: data_type()は何をしますか?それはデフォルトのコンストラクタですか? – lezebulon

+0

それは(または私はそれを変更しました)です。 data_typeは、[]演算子を使用する場合にのみデフォルト構成可能である必要があります。新しいコメントメモとしての割り当ては、キーがすでに存在する場合にのみ必要です。それ以外の場合、insertは実際に挿入されたキーに関連付けられたデータを設定します。 – metal

+0

ForceInsert2でstd :: lower_boundを使用し、それを挿入のヒントとして提供する方がよいでしょう。詳細はScott Meyersの「Effective STL」を参照してください。 – metal

0
myMap[0] = 0; 

これはとほぼ同様であるが存在しない場合、この行は、0のキーと値を挿入し、いずれの場合にも、それは0

にそのキーの値を設定しますあなたは、単一の行にすることができ、持っていたもの:

myMap.insert(std::make_pair(0,0)).first->second = 0; 
+0

ええ、私はイテレータを挿入した要素に戻したいと思っています。 – lezebulon

1

あなたが行うことができます:

map<int, int> m; 
map<int, int>::iterator iter; 
(iter = (m.insert(make_pair(1,1))).first)->second = 5; 

明らかに、make_pairの2番目の値は(正しいタイプである限り)無関係です。

iter = myMap.insert(make_pair(0,0)).first, iter->second = 0; 

カンマ(,)演算子を保証すべての副作用が起きること:ここでは、少し生意気であるために5.に

に値をイテレータのポイントを設定し、技術的にはこれも1つの文になりますrhsが評価される前に、iterが正しい値を持っています

+0

これはうまくいくでしょう。しかし、私はまだこれがうまくいくためには、2番目のタイプ( "1")の無駄なコピーを1つ作る必要があることを迷惑に感じます。明らかにこれはintで大したことではありませんが、より大きな構造はどうですか? – lezebulon

+2

構造体のサイズが十分に大きいので、コピーを複数回作成することが問題になる場合は、キーを最初に見つけて、必要な場合にのみ挿入する方がよいでしょう(テンプレート関数を作成して、論理は何度も)。そのままで、あなたは 'pair'のコピーを作って、それが実際に挿入すればコピーします(とにかくそれを必要とします)。したがって、提案されたバージョンではほとんどのツリーコピーが作成されますが、とにかく少なくとも2つ必要です。 – Attila

1

:ここでは、2つのジェネリック版、最初のより多くのあなたのコードのように上にあるマップの値型は `ペア `ではないことを

int& value = myMap[0] = 0; 
関連する問題