2012-04-13 89 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 '。 – 2012-04-13 20:19:07

+0

插入或編輯,你想要哪一個?很明顯,你已經有了一個插入的單線程,那麼問題到底是什麼? – 2012-04-13 20:20:17

+0

我相信你找到了最有效的方法。如果你只是不喜歡它的外觀,實現一個「替換」功能,結合這兩個步驟,但即使這樣做將按照你的例子來實現。 – Chad 2012-04-13 20:20:40

回答

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 2012-04-13 20:43:21

+0

它是(或者 - 我改變了它)。如果使用[]運算符,data_type只需要默認構造。作爲新的註釋說明,只有在密鑰已經存在的情況下才需要分配。否則,insert事實上會設置與插入的鍵相關的數據。 – metal 2012-04-13 20:52:38

+0

更好的辦法是在ForceInsert2中使用std :: lower_bound,然後將其作爲提示插入。有關更多信息,請參閱Scott Meyers的「Effective STL」。 – metal 2013-02-04 18:23:55

0
myMap[0] = 0; 

這條線將插入爲0的鍵的值,如果它不存在它,並且在任一情況下,將該密鑰的值設置爲0

這大致類似於你有什麼,可製作成一條線:

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

是的,但我也想返回一個迭代器到插入的元素 – lezebulon 2012-04-13 20:21:36

1

你可以這樣做:

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

顯然make_pair中的第二個值是無關緊要的(只要它是正確的類型)。在這裏,您設置的值的迭代器指向到5

是有點厚臉皮,在技術上這也將是一個聲明:

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

逗號(,)運營商保證所有的副作用發生在評估rhs之前,所以iter具有正確的值

+0

好吧,這將工作。但我仍然覺得很煩,你需要製作第二種類型的無用副本(「1」)才能工作。顯然,這對整數並不重要,但更大的結構呢? – lezebulon 2012-04-13 20:39:05

+2

當結構足夠大以至於不止一次複製是一個問題時,您可能會首先發現密鑰並在必要時插入(如果需要,可以創建一個模板函數來執行此操作多次的邏輯)。事實上,你正在爲'pair'製作一個副本,然後在插入副本時再插入副本(無論如何你都需要)。所以建議的版本最多可以生成樹副本,而至少需要兩個樹副本。 – Attila 2012-04-13 20:47:34

1

如果你只是想要的值,而不是對:

int& value = myMap[0] = 0;