マップのC ++マップをループするにはどうすればよいですか?


292

std::mapC ++でループするにはどうすればよいですか?私の地図は次のように定義されています:

std::map< std::string, std::map<std::string, std::string> >

たとえば、上記のコンテナは次のようなデータを保持します。

m["name1"]["value1"] = "data1";
m["name1"]["value2"] = "data2";
m["name2"]["value1"] = "data1";
m["name2"]["value2"] = "data2";
m["name3"]["value1"] = "data1";
m["name3"]["value2"] = "data2";

このマップをループしてさまざまな値にアクセスするにはどうすればよいですか?


25
現代のc ++についてはRiotの回答を受け入れることを検討するかもしれません。
Sergio Basurco、2015年

マップのマップが最小限で完全な検証可能な例になるかどうかは完全にはわかりませんが、要点はわかります。
davidhood2 2016年

3
通知を見逃した場合は、chuckleplantのコメントを繰り返してみましょう。最新のc ++に対するRiotの回答を受け入れることを検討してください。
noɥʇʎԀʎzɐɹƆ

パピーの答えはより用途が広いですが、グーグルたちがライオットの答えをもっと欲しがっている賛成票の数から判断すると、
Legion Daeth 2016年

回答:


563

古い質問ですが、残りの回答はC ++ 11の時点で古くなっています- 範囲ベースのforループを使用して、単純に行うことができます:

std::map<std::string, std::map<std::string, std::string>> mymap;

for(auto const &ent1 : mymap) {
  // ent1.first is the first key
  for(auto const &ent2 : ent1.second) {
    // ent2.first is the second key
    // ent2.second is the data
  }
}

これは以前のバージョンよりもずっときれいで、不必要なコピーを避けます。

コメントを参照変数の明示的な定義(未使用の場合は最適化される)に置き換える方を好む人もいます:

for(auto const &ent1 : mymap) {
  auto const &outer_key = ent1.first;
  auto const &inner_map = ent1.second;
  for(auto const &ent2 : inner_map) {
    auto const &inner_key   = ent2.first;
    auto const &inner_value = ent2.second;
  }
}

13
回答を適切に保つための小道具-私は、これがトップに近づく道になることを望んでいます。おそらくこれを受け入れられた回答に編集することが適切でしょうか?(これはTeX.SXで行うことですが、SOは異なる文化です。)
Sean Allred

2
簡単な質問ですが、const後で書くことの決定に関連性はありますautoか?純粋に美的ですか?
Parham 2014

6
@Parham constは、指定された型の前または後が優先事項ですが、ポインターが使用されている状況ではより明確になるため、右側に置くことを選択します。たとえば、両方int const *xを使用していて、IMOよりも明確なIMO int *const xとして記述できます。ただし、左から右に解析されるだけなので、効果は同じです。この質問への回答をご覧ください:stackoverflow.com/questions/5503352/const-before-or-const-afterint const *const xconst int *const x
Riot

2
&const&ent2の&はどういう意味ですか?
Tanner Summers

5
@TannerSummersは、値でアクセスすると、各要素をコピーする非効率性が高まるためです。さらに、コンテンツを変更する場合は、値ではなく参照(またはポインタ)で要素にアクセスする必要があります。
Riot

308

イテレータを使用できます。

typedef std::map<std::string, std::map<std::string, std::string>>::iterator it_type;
for(it_type iterator = m.begin(); iterator != m.end(); iterator++) {
    // iterator->first = key
    // iterator->second = value
    // Repeat if you also want to iterate through the second map.
}

10
彼がマップを変更するつもりでない限り、const_iteratorを使用する方が良いでしょう。
Michael Aaron Safyan、2011年

28
増分時に不要なコピーを回避するため、反復子++よりも++反復子を使用する方が効率的です。
Game_Overture 2013年

19
自動を使用すると、大幅にC ++ 11のループを簡素化:for(auto iterator = m.begin(); iterator != m.end(); iterator++)
ジェラルド

127
これはc ++ 11ではかなり古くなっています。(auto iter:mymap)のために使用する
匿名エンティティ

37
c ++ 11の場合、潜在的なコピーを回避するために(auto&iter:mymap)を使用する必要があります。
dev_nut 2014年

60
for(std::map<std::string, std::map<std::string, std::string> >::iterator outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter) {
    for(std::map<std::string, std::string>::iterator inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter) {
        std::cout << inner_iter->second << std::endl;
    }
}

またはC ++ 0xでより良い:

for(auto outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter) {
    for(auto inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter) {
        std::cout << inner_iter->second << std::endl;
    }
}

2
auto&を使用するか、マップを変更しない場合はconst auto&を使用する必要があります。さらに、メンバー以外のbegin()およびend()を優先します。つまり、for(const auto&iter = begin(map); ...)です。
Ela782 14

13
あるいはもっと単純です:for(const auto&element:map)cout << element.second;
Ela782 14

26

C ++ 17以降では、「構造化バインディング」機能を使用できます。これにより、単一のタプル/ペアを使用して、名前が異なる複数の変数を定義できます。例:

for (const auto& [name, description] : planet_descriptions) {
    std::cout << "Planet " << name << ":\n" << description << "\n\n";
}

当初の提案(著名ビャーネ・ストロヴストルップ、ハーブサッターとガブリエル・ドス・レイスによっては)読んで楽しいです(と示唆した構文より直感的な私見です)。読むのは退屈ですが実際に入るものに近い標準の提案された表現もあります。


2
C ++ 17がまだ「存在」していないにも関わらず、これはかなり可決されました。男は、クリーンで安全なコードを簡単に記述できるようにすることで、C ++を本当に活性化しています。
ジョナス

24

このようなことをしてください:

typedef std::map<std::string, std::string> InnerMap;
typedef std::map<std::string, InnerMap> OuterMap;

Outermap mm;

...//set the initial values

for (OuterMap::iterator i = mm.begin(); i != mm.end(); ++i) {
    InnerMap &im = i->second;
    for (InnerMap::iterator ii = im.begin(); ii != im.end(); ++ii) {
        std::cout << "map[" 
                  << i->first 
                  << "][" 
                  << ii->first 
                  << "] =" 
                  << ii->second 
                  << '\n';
    }
}   

2番目の場合は++ iiではなく++ iiです:)
Slipstream

最後に「/ n」は「\ n」になるはずだと思う
ケニアコーンケツムブット14

まあ、後で定義を解除するために定義を使用したでしょう。これはC ++ 98の良い方法です:) +1
Ludovic Zenohate Lagouardette

12

C ++ 11:

std::map< std::string, std::map<std::string, std::string> > m;
m["name1"]["value1"] = "data1";
m["name1"]["value2"] = "data2";
m["name2"]["value1"] = "data1";
m["name2"]["value2"] = "data2";
m["name3"]["value1"] = "data1";
m["name3"]["value2"] = "data2";

for (auto i : m)
    for (auto j : i.second)
        cout << i.first.c_str() << ":" << j.first.c_str() << ":" << j.second.c_str() << endl;

出力:

name1:value1:data1
name1:value2:data2
name2:value1:data1
name2:value2:data2
name3:value1:data1
name3:value2:data2

2
この回答は、stackoverflow.com / a / 27344958/3658660とどのように異なりますか?それがどこでもコピーを作成しているという事実を除いて。
hlscalon

1

std::map< std::string, std::map<std::string, std::string> >::const_iteratorマップがconstのときに使用します。


1
ご存知のように、コードを適切なマージンの後ろに隠すのは、良い習慣ではない場合があります。安全であることは理解していますが、コードのビジョンを完全にぼやけています。auto仲間に行くか、vimを使用する彼がKOします。
Ludovic Zenohate Lagouardette 2016

0

なので einpoklumで述べた彼らの答え以来、C ++ 17を使用することもでき宣言を結合構造。私は、マップのマップを快適な方法で反復するための完全なソリューションを提供することによって、それを拡張したいと思います。

int main() {
    std::map<std::string, std::map<std::string, std::string>> m {
        {"name1", {{"value1", "data1"}, {"value2", "data2"}}},
        {"name2", {{"value1", "data1"}, {"value2", "data2"}}},
        {"name3", {{"value1", "data1"}, {"value2", "data2"}}}
    };

    for (const auto& [k1, v1] : m)
        for (const auto& [k2, v2] : v1)
            std::cout << "m[" << k1 << "][" << k2 << "]=" << v2 << std::endl;

    return 0;
}

注1:マップを埋めるために、イニシャライザリストC ++ 11)を使用しました機能)を使用しました。これは、固定された初期化をコンパクトに保つ​​のに便利な場合があります。

注2:mループ内でマップを変更する場合は、constキーワード。

コリルのコード


0

最初の解決策は、次のようにrange_based forループを使用することです。

注:range_expressionのタイプがのstd::map場合、range_declarationのタイプはstd::pairです。

for ( range_declaration : range_expression )      
  //loop_statement

コード1:

typedef std::map<std::string, std::map<std::string, std::string>> StringToStringMap;

StringToStringMap my_map;

for(const auto &pair1 : my_map) 
{
   // Type of pair1 is std::pair<std::string, std::map<std::string, std::string>>
   // pair1.first point to std::string (first key)
   // pair1.second point to std::map<std::string, std::string> (inner map)
   for(const auto &pair2 : pair1.second) 
   {
       // pair2.first is the second(inner) key
       // pair2.second is the value
   }
}

2番目のソリューション:

コード2

typedef std::map<std::string, std::string> StringMap;
typedef std::map<std::string, StringMap> StringToStringMap;

StringToStringMap my_map;

for(StringToStringMap::iterator it1 = my_map.begin(); it1 != my_map.end(); it1++)
{
    // it1->first point to first key
    // it2->second point to inner map
    for(StringMap::iterator it2 = it1->second.begin(); it2 != it1->second.end(); it2++)
     {
        // it2->second point to value
        // it2->first point to second(inner) key 
     }
 }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.