2012-11-27 132 views
2

地圖我有2個元素(現在)地圖:搜索的價值

#define IDI_OBJECT_5001 5001 
#define IDI_OBJECT_5002 5002 
    /.../ 


ResourcesMap[IDI_OBJECT_5001] = "path_to_png_file1"; 
ResourcesMap[IDI_OBJECT_5002] = "path_to_png_file2"; 

我試圖實施該搜索地圖的方法。我傳遞字符串參數(文件路徑)和方法返回INT(地圖的鍵值)

int ResFiles::findResForBrew(string filePath) 
{ 
string value = filePath; 
int key = -1; 
for (it = ResourcesMap.begin(); it != ResourcesMap.end(); ++it) 
{ 
    if (/*checking if it->second == value */) 
    { 
     key = it->first; 
     break; 
    } 
} 
return key; 
} 

類ResFiles { 市民: ResFiles(); 〜ResFiles();

map <int, string> ResourcesMap; 
map <int, string>::const_iterator it; 
void filenamesForBrew(); 
int findResForBrew(string filePath); 

    private: 

};

我該如何檢查它 - > second-> ==值,然後返回該鍵? 我會感謝一些幫助。提前致謝。

+3

那麼'it-> second == value'有什麼問題? – 2012-11-27 10:56:09

+0

你已經擁有了它,只要'if(it-> second == filePath)返回它 - > first;'。 –

+0

我已經試過了,並且可視化標記爲錯誤: 「錯誤C2678:二進制'==':找不到操作符找到類型爲'const std :: string'的左手操作數(或者沒有可接受的轉換) 「 –

回答

2

這是一個基本的實現

template <typename K, typename V> 
    K keyFor(std::map<K, V> const& map, V const& target) 
    { 
     for (typename std::map<K, V>::const_iterator it=map.begin(); it!=map.end(); ++it) 
      if (it->second == target) 
       return it->first; 

     return K(); // or throw? 
    } 

或者,用C++ 11的支持:

  for (auto& pair : map) 
      if (pair.second == target) 
       return pair.first; 
1

你在做什麼應該工作,(只是it->second ==value),但如果你想要一個「高效「查找關鍵值,你應該創建第二個地圖。

有算法,如std::find這將需要一個特殊的謂詞,但他們只是使用下面的循環,並不會更有效,因爲搜索仍然是線性的。

如果你想這樣做了很多(問題設計,如果你是...),並希望有一個特殊的模板,你既可以:

template< typename K, typename V > 
bool findByValue(std::map<K,V> const& theMap, K& key, const V& value) 
{ 
    typename std::map<K,V>::const_iterator iter; 
    for(iter it = theMap.begin(), itEnd = theMap.end(); it != itEnd; ++it) 
    { 
     if(it->second == value) 
     { 
      key = iter->first; 
      return true; 
     } 
    } 
    return false; 
} 

或者自定義謂詞的std :: find_if

template< typename P > 
class Match2nd 
{ 
    typedef typename P::second_type value_type; 
    value_type val; 

    public: 

    explicit Match2nd(value_type const& v) : val(v) 
    { 
    } 

    bool operator()(P const& p) const 
    { 
     return p.second == val; 
    } 
}; 

template< typename M > 
Match2nd< typename M::value_type > 
makeMatch2nd(const M& map, typename M::mapped_type const& v) 
{ 
    return Match2nd<M::value_type>(v); 
} 

然後在你的代碼,你可以:

std::map< int, std::string >::const_iterator iter = 
    std::find_if(ResourcesMap.begin(), ResourcesMap.end(), makeMatch2nd(value)); 

// if iter is end() the key doesn't exist, 
//if it does then iter->first is your key 

,你可以將它放入的C函數ourse ..

用C++ 0x你也可以把Match2nd放入一個lambda表達式並放入std :: find中。然而...

所有這些東西仍然是線性搜索。如果你的地圖很大,用另一種方式放置地圖,或者使用boost :: multi_index或類似的方法。

+0

感謝有關2地圖算法的線索。我的地圖現在很小,但它會很大,而且我非線性搜索。 –

0

好吧,我發現:

int ResFiles::findResForBrew(string filePath) 
{ 
string value = filePath; 
int key = -1; 
for (it = ResourcesMap.begin(); it != ResourcesMap.end(); ++it) 
{ 
    if(it->second.compare(filePath) == 0) 
    { 
     key = it->first; 
     break; 
    } 
} 
return key; 
} 
+0

我不明白爲什麼'it-> second == value'編譯失敗。出於好奇,你使用的是什麼編譯器? – 2012-11-27 11:40:55

+0

我爲C/C++使用Microsoft Visual Studio Express 12 –

+0

我的項目中有* .c和* .cpp文件。這可能會影響到這? –

0

首先,如果你的重點是道路,爲什麼通過ID索引?

如果您按照文件路徑查找,將其用作Key,那麼對於映射的每個鍵尋找特定值的迭代速度都會更快。第二個,恕我直言,我建議使用常量值而不是#define s,#define s沒有鍵入,所以如果執行一些意想不到的數據轉換可能會很麻煩,我是強值類型的忠實粉絲。

試試這個:

// The type of the ID of the Resources. 
typedef int ObjectID; 

// Current resources. 
const ObjectID IDI_OBJECT_5001 = 5001; 
const ObjectID IDI_OBJECT_5002 = 5002; 

// The type of a map containing resources, you can assure that 
// a Resource ID would be stored, as you can see at the mapped type. 
typedef std::map<const std::string, const ObjectID> idpath; 

idpath ResourcesMap; 

第三,我不鼓勵使用map::operator[]的插入值,調用這個操作符,你要創建一個空的對象,然後,通過分配的operator=新價值映射類型;更不用說如果對象已經存在,就會被覆蓋。因此,使用該運營商i的認爲你不是使用map::insert方法做更多的操作:

ResourcesMap.insert(idpath::value_type("path_to_png_file1", IDI_OBJECT_5001)); 
ResourcesMap.insert(idpath::value_type("path_to_png_file2", IDI_OBJECT_5002)); 

所以,最後,如何在你的代碼做:

const ObjectID ID_NULL = 0; 

ObjectID ResFiles::findResForBrew(string filePath) const // note the const ;) 
{ 
    ObjectID Result = ID_NULL; 
    // Perform the built-in map find, better than iterate the whole map. 
    idpath::const_iterator Found = ResourcesMap.find(filePath); 

    if (Found != ResourcesMap.end()) 
    { 
     Result = Found->second; 
    } 

    return Result; 
} 

記住,這個算法假設你可以交換你的鍵盤映射對,如果你不這樣做,你需要迭代整個映射。

+0

我知道使用#define將來會非常危險,但我無法改變它。這是BREW開發中創建資源的一部分。我使用filepath的機制是將另一個用JAVA編寫的項目調整爲BREW技術。這是某種模擬,資源從文件路徑加載。 –