Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

C++のmapとJavaのmapの挙動が違う件

スポンサードリンク

f:id:fa11enprince:20200701021345j:plain
C++でmapを書いててinsertしまくってましたが、
あれれ?Javaと挙動が違うということに気付きました。
mapでinsertするとC++ではキーが重複したときに、
insertされず、valueが上書きされない。
一方、Javaのほうはputしたときに
最後にputしたものでvalueが上書きされる
というようになっていました。

C++のコード

#include <iostream>
#include <string>
#include <unordered_map>

using namespace std;

int main()
{
    unordered_map<string, int> strmap;
    string k;
    int v;
    while (cin >> k >> v)
    {
        if (cin.eof())   // Ctrl+D (Unix/Linux), Ctrl+Z(Windows)
        {
            break;
        }
        strmap.insert({k, v});
    }

    for (const auto& s : strmap)
    {
        cout << s.first << " => " << s.second << '\n';
    }

    return 0;
}

実行結果

途中まで入力してCtrl+DまたはCtrl+Zで終了しています

aaa 1
bbb 1
aaa 2
bbb 2
bbb => 1
aaa => 1

お、おう、わざと無理やり最後の値でinsertするってことが
単純にはできないのか…

Javaのコード

package purin;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            String buf = in.nextLine();
            String[] bufs = buf.split(" ");
            map.put(bufs[0], Integer.parseInt(bufs[1]));
        }
        for (Map.Entry<String, Integer> m : map.entrySet()) {
            System.out.println(m.getKey() + " => " + m.getValue());
        }
        if (in != null) {
            in.close();
        }
    }
}

実行結果

aaa 1
bbb 1
aaa 2
bbb 2
aaa => 2
bbb => 2

うん、普段触ってる言語はこっちの動きだ……

C++で同じようなことを実現する方法

※追記 こんなことしなくてよいです!
詳細は id:yasuharu519 さんのコメントを参照ください。
operator[]で要素追加できるなんて盲点でした(´Д` )!!

#include <iostream>
#include <string>
#include <unordered_map>

using namespace std;

int main()
{
    unordered_map<string, int> strmap;
    string k;
    int v;
    while (cin >> k >> v)
    {
        if (cin.eof())   // Ctrl+D (Unix/Linux), Ctrl+Z(Windows)
        {
            break;
        }
        // not found
        if (strmap.find(k) == strmap.end())
        {
            strmap.insert({k, v});
        }
        // found
        else
        {
            strmap[k] = v;
        }
    }

    for (const auto& s : strmap)
    {
        cout << s.first << " => " << s.second << '\n';
    }

    return 0;
}

実行結果はJavaのと同様なので省略します。

うん。要はちゃんとチェックしろってことですね。
find()で見つからないときは最後の要素の次(iterator::end())を返します。
最後の要素でなくて最後の要素の次ですね。C++を使い慣れている人には常識ですが……。
ここ重要なのでテストに出ます。