さらに先へ · 16
辞書(マップ)
キーで値を探して更新する:単語を数える、あるか確かめる、キー順に回る。
辞書(マップ)は番号ではなくキーで値を探します。
下の例は単語ごとの出現回数を数え、聞かれた単語を探し、キー順にすべて表示します。
words = input().split()queries = input().split()print(len(set(words)))counts = {}for w in words: counts[w] = counts.get(w, 0) + 1for q in queries: if q in counts: print(q, counts[q]) else: print(q, "none")for w in sorted(counts): print(w, counts[w])const [words, queries] = require("fs").readFileSync(0, "utf8").trim().split("\n").map((l) => l.trim().split(/\s+/));console.log(new Set(words).size);const counts = new Map();for (const w of words) counts.set(w, (counts.get(w) ?? 0) + 1);for (const q of queries) { if (counts.has(q)) console.log(q, counts.get(q)); else console.log(q, "none");}for (const w of [...counts.keys()].sort()) console.log(w, counts.get(w));import { readFileSync } from "node:fs";const [words, queries]: string[][] = readFileSync(0, "utf8").trim().split("\n").map((l) => l.trim().split(/\s+/));console.log(new Set(words).size);const counts = new Map<string, number>();for (const w of words) counts.set(w, (counts.get(w) ?? 0) + 1);for (const q of queries) { if (counts.has(q)) console.log(q, counts.get(q)); else console.log(q, "none");}for (const w of [...counts.keys()].sort()) console.log(w, counts.get(w));import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String[] words = sc.nextLine().trim().split("\\s+"); String[] queries = sc.nextLine().trim().split("\\s+"); System.out.println(new HashSet<>(Arrays.asList(words)).size()); Map<String, Integer> counts = new TreeMap<>(); for (String w : words) counts.merge(w, 1, Integer::sum); for (String q : queries) { if (counts.containsKey(q)) System.out.println(q + " " + counts.get(q)); else System.out.println(q + " none"); } for (Map.Entry<String, Integer> e : counts.entrySet()) { System.out.println(e.getKey() + " " + e.getValue()); } }}using System;using System.Collections.Generic;using System.Linq; class Program{ static void Main() { string[] words = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); string[] queries = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); Console.WriteLine(new HashSet<string>(words).Count); var counts = new Dictionary<string, int>(); foreach (string w in words) counts[w] = counts.GetValueOrDefault(w) + 1; foreach (string q in queries) { if (counts.TryGetValue(q, out int c)) Console.WriteLine($"{q} {c}"); else Console.WriteLine($"{q} none"); } foreach (string w in counts.Keys.OrderBy(k => k, StringComparer.Ordinal)) Console.WriteLine($"{w} {counts[w]}"); }}#include <iostream>#include <map>#include <set>#include <sstream>#include <string>#include <vector> std::vector<std::string> readWords() { std::string line, w; std::getline(std::cin, line); std::istringstream in(line); std::vector<std::string> out; while (in >> w) out.push_back(w); return out;} int main() { std::vector<std::string> words = readWords(), queries = readWords(); std::cout << std::set<std::string>(words.begin(), words.end()).size() << '\n'; std::map<std::string, int> counts; for (const auto& w : words) counts[w]++; for (const auto& q : queries) { if (counts.contains(q)) std::cout << q << ' ' << counts.at(q) << '\n'; else std::cout << q << " none\n"; } for (const auto& [w, c] : counts) std::cout << w << ' ' << c << '\n';}#include <stdio.h>#include <stdlib.h>#include <string.h> char keys[1000][32];int vals[1000], n = 0; int find(const char *w) { for (int i = 0; i < n; i++) if (strcmp(keys[i], w) == 0) return i; return -1;} int cmp(const void *a, const void *b) { return strcmp(keys[*(const int *)a], keys[*(const int *)b]); } int main(void) { char line[4096], qline[4096]; fgets(line, sizeof line, stdin); fgets(qline, sizeof qline, stdin); for (char *w = strtok(line, " \r\n"); w; w = strtok(NULL, " \r\n")) { int i = find(w); if (i < 0) { strcpy(keys[n], w); vals[n] = 0; i = n++; } vals[i]++; } printf("%d\n", n); for (char *q = strtok(qline, " \r\n"); q; q = strtok(NULL, " \r\n")) { int i = find(q); if (i >= 0) printf("%s %d\n", q, vals[i]); else printf("%s none\n", q); } int order[1000]; for (int i = 0; i < n; i++) order[i] = i; qsort(order, n, sizeof order[0], cmp); for (int i = 0; i < n; i++) printf("%s %d\n", keys[order[i]], vals[order[i]]); return 0;}words = コンソール.行読み().分ける();queries = コンソール.行読み().分ける();counts = 辞書();それぞれ (w の中 words){ もし (counts.含む(w)) { counts[w] = counts[w] + 1; } でなければ { counts[w] = 1; }}コンソール.書く(counts.個数);それぞれ (q の中 queries){ もし (counts.含む(q)) { コンソール.書く(q + " " + counts[q]); } でなければ { コンソール.書く(q + " none"); }}keys = counts.キー一覧;keys.並べ替え();それぞれ (w の中 keys){ コンソール.書く(w + " " + counts[w]);}apple banana apple cherry banana apple banana grape
3 banana 2 grape none apple 3 banana 2 cherry 1
ポイント
"apple" → 3のようにキーと値を組にしておきます。
追加・検索・更新は、リストを先頭から調べるよりずっと速くできます。- いちばんよくある使い方は数えることです。
初めて見た単語は 0 から始めて 1 を足します。 - ないキーを読んだときの動きが言語ごとにいちばん違います。
エラーになる、空の値が返る、新しい要素ができる。
だから先にあるか確かめます。 - 回る順番を当てにしないでください。
入れた順を守る言語も、順番を約束しない言語もあります。
例はどの言語でも同じになるよう、キーを並べ替えて表示します。 - 値なしでキーだけを集めたものが集合です。
異なる単語の数は集合の大きさでそのまま求まります。
言語ごとの書き方
| Python | counts = {} — 数えるのは counts.get(w, 0) + 1、確認は w in counts。ないキーを [] で読むと KeyError。入れた順を守ります。 集合は set |
|---|---|
| JavaScript | new Map() — 数えるのは (counts.get(w) ?? 0) + 1、確認は has。ないと get は undefined。入れた順を守ります。 集合は Set |
| TypeScript | JavaScript と同じです。new Map<string, number>() のように型を書きます |
| Java | HashMap(順番の約束なし)、LinkedHashMap(入れた順)、TreeMap(キー順)。数えるのは merge(w, 1, Integer::sum)、確認は containsKey、ないと get は null。集合は HashSet |
| C# | Dictionary<string, int> — 数えるのは GetValueOrDefault(w) + 1、確認は TryGetValue。ないキーをインデクサーで読むと KeyNotFoundException。順番は未定義です(キー順は SortedDictionary)。集合は HashSet |
| C++ | std::map(キー順)、std::unordered_map(順番の約束なし)。数えるのは counts[w]++、確認は C++20 の contains。ないキーを [] で読むと値 0 の要素ができます。集合は std::set |
| C | 辞書がありません。 例はキーの配列と値の配列を並べて持ち、先頭から探します(小さな入力なら十分です) |
| Craykon | 辞書() — d["りんご"] = 3 で入れて読みます。確認は d.含む(キー)、d.キー一覧 は入れた順。ないキーを読むと Python と同じく実行時エラーで止まります |
よくある間違い
ないキーをそのまま読んだPython · C# · Craykon
counts = {"apple": 3}
print(counts["grape"])→ KeyError: 'grape' で止まります(C# は KeyNotFoundException、Craykon は辞書に "grape" キーがないというエラー)
先にあるか確かめるか、Python の get(w, 0) のように既定値を渡します。
入れた順に出てくると思ったJava · C# · C++
Map<String, Integer> m = new HashMap<>();
m.put("pear", 1); m.put("apple", 2); m.put("fig", 3);
System.out.println(m.keySet());→ [apple, pear, fig] — 入れた順(pear, apple, fig)と違います
キーを並べ替えてから表示するか、順番を約束する TreeMap・LinkedHashMap(C++ std::map、C# SortedDictionary)を使います。
確かめるつもりで [] で読んだら要素ができたC++
std::map<std::string, int> counts;
if (counts["grape"] == 0) { }
std::cout << counts.size();→ 1 — 読んだだけなのに "grape" の要素が値 0 でできました
確認は counts.contains(w)(C++20)か counts.find(w) で行います。
言語ごとの違い
JavaScript で空のオブジェクト
数えるには
JavaScript で空のオブジェクト
{} を使って数えると、"constructor" のような単語が Object.prototype のものとぶつかり、"10" のような数の形のキーは入れた順に関係なく先頭に昇順で並びます。数えるには
Map を使いましょう。