特定のキーがC ++ std :: mapに存在するかどうかを確認する方法


450

指定されたキーがマップ内にあるかどうかを確認しようとしていますが、それができません。

typedef map<string,string>::iterator mi;
map<string, string> m;
m.insert(make_pair("f","++--"));
pair<mi,mi> p = m.equal_range("f");//I'm not sure if equal_range does what I want
cout << p.first;//I'm getting error here

では、pの内容をどのように印刷できますか?


std::pair<iterator,bool> insert( const value_type& value );それが返すブールは何ですか?鍵がすでに存在するかどうかはわかりますか?
krithikaGopalakrisnan

回答:


691

使用する map::find

if ( m.find("f") == m.end() ) {
  // not found
} else {
  // found
}

105
あなただけの特定のキーが存在するかどうかを確認したい場合は、おそらく、むしろ使用したいmap::count
tomsmeding

10
@tomsmeding std :: mapにはキーが1つしかありません。したがって、countは0または1のいずれかになります。一方が他方より効率的ですか?
goelakash

34
@goelakashはほとんどありません。それだけということだcount戻っintしばらくはfind全体のイテレータを返します。イテレータの構成を保存します:)もちろん、後でその値が存在する場合にそれを使用する場合は、findを使用してその結果を保存します。
tomsmeding 2015

9
@tomsmedingマルチマップを使用している場合は、コンテナ全体を調べる必要があります。その場合、find()の方が高速です。
Trevor Hickey

11
スピードを探している人に: countfindユニークなキーを必要とマップを使用する際の速度でほぼ同じです。(1)特定の順序を維持するために要素が必要ない場合は、std :: unordered_mapを使用します。これは、ほぼ一定のルックアップを備えており、複数のペアを格納する場合に非常に役立ちます。(2)それが存在する場合は、値を使用したい場合は、2ルックアップを防ぐための::検索結果を保存し、イテレータを使用しますauto it = m.find("f"); if (it != m.end()) {/*Use it->second*/}
cdgraham

305

マップ内の特定のキーが存在するかどうかを確認するにcountは、次のいずれかの方法でメンバー関数を使用します。

m.count(key) > 0
m.count(key) == 1
m.count(key) != 0

ドキュメントmap::findは、「別のメンバー関数、をmap::count使用して、特定のキーが存在するかどうかを確認することができます。」

ドキュメントmap::countは、「マップコンテナ内のすべての要素は一意であるため、関数は1(要素が見つかった場合)または0(それ以外の場合)のみを返すことができます。」

存在することがわかっているキーを介してマップから値を取得するには、map :: atを使用します

value = m.at(key)

異なり、マップ::演算子[]はmap::at指定されたキーが存在しない場合、マップ内の新しいキーを作成しません。


33
両方の操作を実行する場合は、それが存在するかどうかを確認してから、それについて何かしてください。find代わりに使用してください。がsecond返すイテレータの属性をfind使用して、キーの値を取得できます。使用する場合countatまたはoperator[]1つしか使用できなかったときに2つの操作を実行する場合。
OdraEncoded 2014年

1
> 0、== 1、!= 0を実行する必要はありません。これは、C ++がifステートメント(条件!= 0)で行う正確なチェックなので、次のように使用できますif(m.count(key))
jv110

6
@ jv110 Microsoft C ++コンパイラは、からのキャストを検出すると警告を発行intboolます。同様の警告を発行しない他のC ++コンパイラもありますが、私は明示的な比較を使用して意図を明確にし、読みやすさを向上させることを好みます。C#などの他の言語では、微妙なプログラミングエラーが発生する可能性を防ぐために、このような暗黙の変換は禁止されています。
DavidRR

カウントの時間の複雑さは何ですか?それは単なるO(1)操作ですか?
Mazeryt

1
@Mazeryt C ++標準ライブラリのクラスについて話していることを考えると、確かにそうだと思います。言語にとらわれない質問の議論については、ハッシュテーブルを本当にO(1)にすることができますか?をご覧ください
DavidRR

47

C ++ 20std::map::containsそれを可能にします。

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

int main()
{
    std::map<int, std::string> example = {{1, "One"}, {2, "Two"}, 
                                     {3, "Three"}, {42, "Don\'t Panic!!!"}};

    if(example.contains(42)) {
        std::cout << "Found\n";
    } else {
        std::cout << "Not found\n";
    }
}

34
私はそれを言うと思います:最後に。
Erik Campobadal

2
時間について.....
リドゥヴァルシャン

39

使用できます.find()

map<string,string>::iterator i = m.find("f");

if (i == m.end()) { /* Not found */ }
else { /* Found, i->first is f, i->second is ++-- */ }

15
m.find == m.end() // not found 

他のAPIを使用する場合は、go for m.count(c)>0

 if (m.count("f")>0)
      cout << " is an element of m.\n";
    else 
      cout << " is not an element of m.\n";

12

あなたが欲しいと思うmap::findm.find("f")がに等しい場合m.end()、キーは見つかりませんでした。それ以外の場合、findは見つかった要素を指すイテレータを返します。

エラーはp.first、ストリーム挿入では機能しないイテレータであるためです。最後の行をに変更しますcout << (p.first)->first;pイテレータのペアが、あるp.first、イテレータであるp.first->firstキー文字列です。

マップは特定のキーに対して1つの要素しか持つことができないため、equal_rangeあまり役に立ちません。すべての連想コンテナに対して定義されているため、マップに対して定義されていますが、マルチマップにとってははるかに興味深いものです。


実際、これはマップへのイテレータのペアであるため、「cout << p.first-> first;」である必要があります。
stefaanv 2009

正解です、ありがとう。それがコードをコンパイルしないことで得られるものです。そして、あなたは(削除されたコメントで)妥当性のチェックについて正しいですが、私は彼がp.firstを印刷できなかった理由を説明しようとしていましたが、それが無効だからではありません-「f」が見つかることはわかっています。equal_rangeの使用はまったくお勧めしませんので、そのためのエラーチェックコードは表示しません。
スティーブジェソップ

うわー、あなたは本当にSOをスキャンしています。あなたの主張が明確だったので、完全を期すために追加しました。以前の回答に有効性チェックを追加しましたが、あなたの回答は私に勝っていたので、それは削除しました。
stefaanv 2009

はい、私が投稿したときにあなたのコメントが表示されたので、私はそれをまったく見ませんでした。
スティーブジェソップ

12

C++17でこれをもう少し単純化しましたIf statement with initializer。このようにして、ケーキを持ち、それを食べることもできます。

if ( auto it{ m.find( "key" ) }; it != std::end( m ) ) 
{
    // Use `structured binding` to get the key
    // and value.
    auto[ key, value ] { *it };

    // Grab either the key or value stored in the pair.
    // The key is stored in the 'first' variable and
    // the 'value' is stored in the second.
    auto mkey{ it->first };
    auto mvalue{ it->second };

    // That or just grab the entire pair pointed
    // to by the iterator.
    auto pair{ *it };
} 
else 
{
   // Key was not found..
}

4
map<string, string> m;

キーが存在するかどうかを確認し、発生数を返します(マップでは0/1):

int num = m.count("f");  
if (num>0) {    
    //found   
} else {  
    // not found  
}

キーが存在するかどうかを確認し、イテレータを返します:

map<string,string>::iterator mi = m.find("f");  
if(mi != m.end()) {  
    //found  
    //do something to mi.  
} else {  
    // not found  
}  

あなたの質問では、悪いoperator<<過負荷によって引き起こされたエラーp.firstmap<string, string>、それを印刷することができません。これを試して:

if(p.first != p.second) {
    cout << p.first->first << " " << p.first->second << endl;
}

1
あなたはタイプミスを持っています。「cout」を「count」に変更
Rivka

1
そして、そのタイプミスは、誰かcoutとは非常に異なる何かを意味する可能性があるため、実際に誰かを捨てることができますcount
modulitos

4
template <typename T, typename Key>
bool key_exists(const T& container, const Key& key)
{
    return (container.find(key) != std::end(container));
}

もちろん、もっと凝ったものにしたい場合は、次のように、見つかった関数と見つからなかった関数を同時に使用する関数をいつでもテンプレート化できます。

template <typename T, typename Key, typename FoundFunction, typename NotFoundFunction>
void find_and_execute(const T& container, const Key& key, FoundFunction found_function, NotFoundFunction not_found_function)
{
    auto& it = container.find(key);
    if (it != std::end(container))
    {
        found_function(key, it->second);
    }
    else
    {
        not_found_function(key);
    }
}

次のように使用します。

    std::map<int, int> some_map;
    find_and_execute(some_map, 1,
        [](int key, int value){ std::cout << "key " << key << " found, value: " << value << std::endl; },
        [](int key){ std::cout << "key " << key << " not found" << std::endl; });

これの欠点は良い名前になり、 "find_and_execute"は扱いにくく、頭のてっぺんからこれ以上良いものを思いつくことはできません...


3

すべての答えがmap :: iterator i = m.find( "f");の上で実行されているため、マップ 'm'の場合のように、検索結果を最後と比較する際は注意してください。

 if (i == m.end())
 {
 }
 else
 {
 }  

キーまたは値を出力するなどの操作をm.end()と等しい場合はイテレータiで実行しないでください。それ以外の場合は、セグメンテーションエラーが発生します。


0

std :: map :: findとstd :: map :: countのコードを比較すると、最初のコードはパフォーマンス上の利点をもたらす可能性があります。

const_iterator find(const key_type& _Keyval) const
    {   // find an element in nonmutable sequence that matches _Keyval
    const_iterator _Where = lower_bound(_Keyval); // Here one looks only for lower bound
    return (_Where == end()
        || _DEBUG_LT_PRED(this->_Getcomp(),
            _Keyval, this->_Key(_Where._Mynode()))
                ? end() : _Where);
    }

size_type count(const key_type& _Keyval) const
    {   // count all elements that match _Keyval
    _Paircc _Ans = equal_range(_Keyval); // Here both lower and upper bounds are to be found, which is presumably slower.
    size_type _Num = 0;
    _Distance(_Ans.first, _Ans.second, _Num);
    return (_Num);
    }

0

この質問にはすでにいくつかの良い答えがあることは知っていますが、私の解決策は共有する価値があると思います。

これは、両方のために働くstd::mapstd::vector<std::pair<T, U>>し、C ++ 11から入手可能です。

template <typename ForwardIterator, typename Key>
bool contains_key(ForwardIterator first, ForwardIterator last, Key const key) {
    using ValueType = typename std::iterator_traits<ForwardIterator>::value_type;

    auto search_result = std::find_if(
        first, last,
        [&key](ValueType const& item) {
            return item.first == key;
        }
    );

    if (search_result == last) {
        return false;
    } else {
        return true;
    }
}

-5

マップのペアを比較したい場合は、このメソッドを使用できます:

typedef map<double, double> TestMap;
TestMap testMap;
pair<map<double,double>::iterator,bool> controlMapValues;

controlMapValues= testMap.insert(std::pair<double,double>(x,y));
if (controlMapValues.second == false )
{
    TestMap::iterator it;
    it = testMap.find(x);

    if (it->second == y)
    {
        cout<<"Given value is already exist in Map"<<endl;
    }
}

これは便利なテクニックです。


C ++プログラミングの初心者として、私はこの答えがなぜ反対票であるのか本当に興味があります。なぜこの回答は人気がないのですか?
gromit190 2017年

3
@ gromit190は、std :: mapにすでにこの機能がある場合に、キーが存在するかどうかを確認するために他のデータ構造全体を使用しているためです。これには、2つのデータ構造間の同期も必要です。これは、誰も処理したくない依存関係です。
Lambage

-5
map <int , char>::iterator itr;
    for(itr = MyMap.begin() ; itr!= MyMap.end() ; itr++)
    {
        if (itr->second == 'c')
        {
            cout<<itr->first<<endl;
        }
    }

3
コードについて詳しく説明してください。説明のないスニペットは、長期的には役に立ちません。
iBug
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.