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 { public: ResFiles(); ~ResFiles();

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

    private:

};

it->second-> == 値を確認し、そのキーを返すにはどうすればよいですか? 助けていただければ幸いです。前もって感謝します。

4

4 に答える 4

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;
于 2012-11-27T11:00:27.530 に答える
1

あなたがやっていることはうまくいくはずですが(ちょうどit->second ==value)、「効率的な」検索値をキーにしたい場合は、2番目のマップを作成する必要があります。

特別な述語を必要とするようなアルゴリズムがあります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++0x では、Match2nd をラムダに入れ、std::find に入れることもできます。でも...

これらはすべて線形検索のままです。マップが大きい場合は、別の方法でマップを配置するか、boost::multi_index などを使用します。

于 2012-11-27T11:02:36.153 に答える
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;
}
于 2012-11-27T11:35:18.143 に答える
0

まず、キーがパスの場合、なぜ ID でインデックスを作成するのでしょうか?

ファイルパスで調べる場合は、それをキーとして使用します。特定の値を探すためにマップの各キーを反復するよりも高速です。

#define2 つ目は、s の代わりに const 値を使用することをお勧めします。s に#defineは型がないため、予期しないデータ変換が実行されると面倒になる可能性があります。

これを試して:

// 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;

3 番目に、値を挿入するために を使用することはお勧めしません。空のmap::operator[]オブジェクトを作成しているこの演算子を呼び出してから、マップされた型のを介して新しい値を割り当てます。オブジェクトが既に存在する場合は上書きされることは言うまでもありません。したがって、この演算子を使用すると、メソッドを使用するよりも多くの操作を行っていると思います:operator=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;
}

このアルゴリズムは、キー マップ ペアを交換できることを前提としていることを思い出してください。そうでない場合は、マップ全体を反復する必要があります。

于 2012-11-27T11:49:00.557 に答える