1. 2 users, 2 orders
  2. single user with multiple orders, order preserved
  3. 3 users, 3 orders mixed
  4. no orders returns empty array
コース一覧
コンピューターサイエンス入門:理論編
キーで join (map 利用)

コンピューターサイエンス入門:理論編

2 進数、論理演算、ビット演算、データ構造、計算量、メモリモデルなど、プログラミングの土台となるコンピュータサイエンスの理論知識を学べるコースです。プログラミングを始めたばかりの学習者や、CS の体系的な土台を作りたい現役エンジニアを対象としています。約 13 時間 (1 日 30 分 × 26 日) で 53 レッスンを修了でき、修了後はコードのパフォーマンスや設計判断の根拠を理解した上で実装できるようになります。

1
2進数とビット演算
01. 2進数から10進数への変換5分
02. 10進数から2進数への変換5分
03. ビットAND演算でフラグ判定5分
04. OR / XOR でフラグを操作する5分
05. popcount で 1 のビット数を数える5分
06. シフト演算で 2 倍 / 半分5分
07. 16 進数から 10 進数への変換5分
08. 第 1 章まとめクイズ5分
2
文字コードと真偽値ロジック
01. 文字 → ASCII コード5分
02. コード → 文字5分
03. UTF-8 のバイト長を返す5分
04. AND / OR の真理値表5分
05. NOT / XOR の真理値表5分
06. 含意 (→) を AND/OR/NOT で表現5分
07. ド・モルガンの法則5分
08. 第2章まとめクイズ5分
3
計算量とBig-O
01. forループの実行回数を返す5分
02. 入れ子ループの実行回数5分
03. 線形探索 (O(n))5分
04. 二分探索 (O(log n))5分
05. バブルソート5分
06. 配列の最大と最小5分
07. 累積和で範囲合計5分
08. 第3章まとめクイズ5分
4
データ構造 (基本)
01. スタック (push/pop) を実装する5分
02. キュー (enqueue / dequeue) を実装する5分
03. カッコのバランス判定 (スタック応用)5分
04. set で重複を除去する5分
05. map で出現回数を数える5分
06. 二数の和 (map で O(n))5分
07. アナグラム判定5分
08. 第 4 章クイズ — データ構造 (基本)5分
5
ファイル / メモリ / IO 概念
01. バイト → KB 変換5分
02. ディスクサイズフォーマット5分
03. キャッシュヒット率5分
04. LRU 簡易シミュレーション5分
05. エンディアンの入れ替え (uint32)5分
06. バッファ範囲チェック5分
07. 第5章まとめクイズ5分
6
ネットワークと符号化
01. Base64 エンコード後の長さ計算5分
02. URL エンコード対象文字数5分
03. IPv4 アドレスを 32bit 整数に変換5分
04. 32bit 整数を IPv4 アドレスに変換5分
05. CIDR プレフィックスからネットマスクを作る5分
06. 単純チェックサム5分
07. 第6章まとめクイズ5分
7
設計と DB 基礎
01. 重複データを 1NF に変換 (フラットなリスト化)5分
02. キーで join (map 利用)5分
03. 残高転送のトランザクション風処理5分
04. CAP の availability 模擬5分
05. URL ルーティング5分
06. 疎結合と密結合 — 依存性注入で設計を変える12分
07. コース総まとめクイズ5分

キーで join (map 利用)

注文のデータに、名前は書かれていない

注文 1 件ごとに持っているのは user_id という番号だけで、名前は入っていません。手を抜いたわけではなく、名前を注文側にも書き写すと、改名が起きたときに過去の注文を全部直す羽目になるからです。名前は 1 か所に置いて、注文側は番号でそこを指す。この「別の一覧の目印を指しているだけの値」を外部キーと呼びます。

そのぶん、画面に名前を出すときは取りに行く必要があります。素直に書くと、注文 1 件ごとにユーザー一覧を先頭から見ることになります。

Python

for order in orders: for user in users: if user["user_id"] == order["user_id"]: print(user["name"], order["amount"])

動きはします。テストも通ります。ただし、ユーザーが 10 万人、注文が 100 万件になると比較の回数は掛け算で効いてきて、1000 億回に届きます。第 3 章で見た二重ループの重さがそのまま出てくる形です。

探すのをやめて、先に引ける形を作る

内側のループは「この番号の人は誰か」を毎回ゼロから調べ直しています。一度調べた結果を捨てているのが無駄です。番号から名前を引ける表を先に 1 回だけ作っておけば、あとは一発で引けます。

内線番号で言えば、こういうことをしておく形です。

Python

book = {} for name, ext in [["佐藤", 1201], ["鈴木", 1204]]: book[name] = ext book["鈴木"] # 1204

辞書は、中に何件入っていても 1 件を引く時間がほぼ変わりません。作るのに n 回、引くのに m 回で、合計は n + m に収まります。100 万件でも待たされません。データベースが JOIN を実行するときも、内部ではこれと同じことをしています。hash join と呼ばれる古典的な手です。

無い番号を引いたときの振る舞いが、言語で違う

Python

book["田中"] # KeyError: '田中'

Python はその場で落ちます。JavaScript は undefined を返して黙って進むので、名前の欄が空のまま画面に出ます。落ちるほうが親切なこともあれば、止まると困ることもあります。

今回の課題では、対応するユーザーが必ず存在する前提でかまいません。ただし実務では、退会したユーザーの注文だけが残っている状態は普通に起きます。既定値を入れるのか、その行を出さないのかを決めておいてください。

やってみよう

joinOrders(users, orders) を完成させてください。

  1. users から、user_id を渡すと name が返る辞書(JavaScript なら Object)を 1 回だけ作る
  2. orders を 1 周し、各注文の user_id でその辞書を引いて名前を得る
  3. name order_id amount の 3 つを持つ形にして並べる。並び順は orders のまま変えない

冒頭の二重ループでもテストは通ります。通ってしまうので、通ったあとに「辞書を先に作る形になっているか」を自分で見直してください。

要件

  1. users から user_id をキー、name を値とするマップ(dict / Object)を作る
  2. orders の各要素から user_id で name を引いて { name, order_id, amount } を生成する
  3. 出力の並び順は入力 orders の順番を維持する

入出力例

joinOrders([{"name":"Alice","user_id":1},{"name":"Bob","user_id":2}], [{"amount":1200,"order_id":101,"user_id":1},{"amount":800,"order_id":102,"user_id":2}]) → [{"amount":1200,"name":"Alice","order_id":101},{"amount":800,"name":"Bob","order_id":102}] joinOrders([{"name":"Alice","user_id":1}], [{"amount":1200,"order_id":101,"user_id":1},{"amount":500,"order_id":103,"user_id":1}]) → [{"amount":1200,"name":"Alice","order_id":101},{"amount":500,"name":"Alice","order_id":103}] joinOrders([{"name":"Alice","user_id":1},{"name":"Bob","user_id":2},{"name":"Carol","user_id":3}], [{"amount":700,"order_id":201,"user_id":3},{"amount":300,"order_id":202,"user_id":1},{"amount":1500,"order_id":203,"user_id":2}]) → [{"amount":700,"name":"Carol","order_id":201},{"amount":300,"name":"Alice","order_id":202},{"amount":1500,"name":"Bob","order_id":203}] joinOrders([{"name":"Alice","user_id":1}], []) → []

ヒント

Python なら辞書内包表記 `{ u['user_id']: u['name'] for u in users }` が簡潔

JavaScript なら `for...of` でループしながら `userMap[u.user_id] = u.name` と入れていく

二重ループ(users × orders)にすると O(n × m) になり遅い。必ず先にマップを作る

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/05/19·更新 2026/08/26

関連レッスン

  • 残高転送のトランザクション風処理

    口座間の残高転送を、ACID の Atomicity(原子性)を満たすように実装します。残高不足ならロールバックして変更しません。

  • CAP の availability 模擬

    CAP 定理の Availability(可用性)を、複数ノード上の最新値を多数決で返す関数として実装します。

  • URL ルーティング

    URL パスを `Controller#action` の文字列に振り分けるルーティングを実装し、MVC の「Controller の入口」を体感します。

  • 疎結合と密結合 — 依存性注入で設計を変える

    疎結合と密結合の違いを比喩・図・コードで理解する。依存性注入(DI)で結合度を下げると、テスト容易性と変更耐性が同時に上がる。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • 外部キーテーブル同士を結びつける鍵
  • テストバグを見つける工程
  • ループ繰り返し処理。矢印で戻すか専用記号で示す
  • データベースデータを構造化して保存する仕組み
  • JOIN複数テーブルをくっつけて 1 つの結果に並べる SQL
  • JavaScriptWeb で動的な振る舞いを担う言語
main.py
学習モード
エディタを読み込んでいます

メモ

キーで join (map 利用)

⌘S で保存