CODE Polyglot / 入門 / 第10回

単語を数える — 辞書(連想配列)と、出てきた順

受け取った単語がそれぞれ何回出てきたかを、はじめて出てきた順に出します。辞書(連想配列・map)は、言語によって「取り出す順番」の決まりが違います。

画面にこう出れば正解

どの言語で書いても、同じ入力なら画面に出る文字は1文字も違わない、というのが正解の決め方です(例は Python で動かしたときのコマンドです)。

日本語の単語

$ python3 wordcount.py りんご みかん りんご
りんご: 2
みかん: 1

英字

$ python3 wordcount.py b a b c a b
b: 3
a: 2
c: 1

数字の言葉

$ python3 wordcount.py 2 10 2 1
2: 2
10: 1
1: 1

1つだけ

$ python3 wordcount.py x
x: 1

何もない

$ python3 wordcount.py
単語がありません

大文字と小文字は別の単語

$ python3 wordcount.py Go go GO go
Go: 1
go: 2
GO: 1

10言語のプログラム

どれもそのまま保存して動かせます。毎朝、上の正解の例をすべて実際に動かして確かめています。

wordcount.php8.4.26 で 6 / 6 件の出力が正解と一致

<?php
// 受け取った単語がそれぞれ何回出てきたかを、はじめて出てきた順に出す
$words = array_slice($argv, 1);
if (count($words) === 0) {
    echo "単語がありません\n";
    exit;
}

// 連想配列は入れた順を保つが、"10" のようなキーは整数の 10 に変わる。順番は別の配列 $order に記録する
$counts = [];
$order = []; // はじめて出てきた順
foreach ($words as $w) {
    if (!isset($counts[$w])) {
        $order[] = $w;
        $counts[$w] = 0;
    }
    $counts[$w]++;
}

foreach ($order as $w) {
    echo $w . ": " . $counts[$w] . "\n";
}

動かし方(ファイルを保存したフォルダで) ・ PHP を入れる

$ php wordcount.php りんご みかん りんご

言語でつまずきやすいところ

初心者がよく書く形(各言語で最初に習う書き方をそのまま使ったもの)を、同じ正解表で動かした結果です。言語を出した答えごとにまとめ、赤い字はその言語が実際に出した間違った行です。

入力初心者がよく書く形の答え(10言語)
日本語の単語りんご みかん りんご
  • Swiftみかん: 1
    りんご: 2
  • PHP・Python・Go・JavaScript・Java・C#・Rust・Ruby・Kotlin✓ 正解
英字b a b c a b
  • Javaa: 2
    b: 3
  • Rust・Swifta: 2
    c: 1
    b: 3
  • PHP・Python・Go・JavaScript・C#・Ruby・Kotlin✓ 正解
数字の言葉2 10 2 1
  • JavaScript・Java・Rust1: 1
    2: 2
    10: 1
  • Swift10: 1
    1: 1
    2: 2
  • PHP・Python・Go・C#・Ruby・Kotlin✓ 正解
1つだけx

✓10言語すべて正解

何もない

✓10言語すべて正解

大文字と小文字は別の単語Go go GO go
  • Gogo: 2
    GO: 1
    Go: 1
  • RustGO: 1
    Go: 1
    go: 2
  • PHP・Python・JavaScript・Java・C#・Ruby・Kotlin・Swift✓ 正解

この回でやること

  • 辞書(連想配列・map)に「単語 → 回数」を記録する
  • はじめて出てきた順に、結果を出す

解説

辞書は「名前で引ける表」

辞書は、「りんご → 2」「みかん → 1」のように、名前(キー)で値を引ける入れ物です。言語によって dict(Python)、Map・オブジェクト(JavaScript)、map(Go)、HashMap・LinkedHashMap(Java・Kotlin)、Dictionary(C#)、Hash(Ruby)、連想配列(PHP)と呼び名が変わります。

取り出す順番は、言語ごとに決まりが違う

辞書から全部を取り出すとき、どの順番で出てくるかは言語によって違います。初心者がよく使う辞書で、実際に試した結果は次のとおりです。

辞書取り出す順番
Python dict・Ruby Hash・PHP 連想配列・Kotlin mutableMapOf入れた順に出てくることが決まっている
Go map・Rust HashMap・Swift Dictionary決まっておらず、動かすたびに変わる(同じ入力でも、通ったり落ちたりする)
Java HashMap決まっていない。毎回同じ順に出るが、入れた順ではない(6件中4件)
C# Dictionary決まっていない。今回の入力では入れた順に出た(6件中6件)が、要素を消したりすると崩れる
JavaScript のオブジェクト {}文字のキーは入れた順だが、数字に見えるキー("2" や "10")だけ先に小さい順で並ぶ(6件中5件)

「今回は通った」と「順番が決まっている」は別のことです。C# のように、たまたま入れた順に出ていても、言語の決まりとして約束されていなければ、頼らないほうが安全です。

この回の正解は「はじめて出てきた順」です。順番が決まっていない辞書を使うときは、出てきた順を別の並び(リスト・配列)に記録しておき、その順に取り出します。Java・Kotlin なら、入れた順を保つ LinkedHashMap を使う方法もあります。JavaScript なら、オブジェクトの代わりに Map を使うと入れた順に出てきます。

大文字と小文字

「Go」「go」「GO」は、別の単語として数えます。同じ単語として数えたいときは、先に小文字にそろえます。

練習

  1. 回数の多い順に並べ替えて出してみましょう
  2. 大文字と小文字を区別しないで数えてみましょう