1. Alice has 3 hobbies, Bob has 1
  2. single user with comma-only spaces handled
  3. value with leading/trailing spaces is trimmed
  4. empty values are skipped
  5. two rows with multi-value each
コース一覧
コンピューターサイエンス入門:理論編
重複データを 1NF に変換 (フラットなリスト化)

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

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分

重複データを 1NF に変換 (フラットなリスト化)

1 つのセルに詰めると、あとで数えられない

蔵書の一覧を表計算ソフトで作ると、タグの欄はたいていこうなります。

書名タグ
深夜特急旅行, エッセイ
銀河鉄道の夜童話
地球の歩き方旅行

眺めるぶんには困りません。困るのは「旅行タグの本は何冊あるか」を数えようとしたときです。第 4 章でやったように辞書で数え上げると、次のようになります。

Python

books = [ ["深夜特急", "旅行, エッセイ"], ["銀河鉄道の夜", "童話"], ["地球の歩き方", "旅行"], ] counts = {} for title, tags in books: counts[tags] = counts.get(tags, 0) + 1 # {'旅行, エッセイ': 1, '童話': 1, '旅行': 1}

旅行の本は 2 冊あるのに、どちらも 1 と出ます。"旅行, エッセイ" と "旅行" が別のキーとして数えられているからです。検索でも同じことが起きます。tags == "旅行" で絞ると 1 行目が漏れ、部分一致に逃げると 旅行記 のような別のタグまで拾ってしまいます。

原因は 1 か所で、1 つのマスに複数の値が入っていることです。これをやめて 1 行 1 値に開くと、深夜特急の行が 2 行に増えて、タグの欄には 旅行 と エッセイ が 1 つずつ入ります。この形をデータベースの世界では第一正規形(1NF)と呼びます。

分ける道具は split、そのあと strip

カンマで区切られた文字列は split で分けられます。ただし、分けただけでは使えません。

Python

"旅行, エッセイ".split(",") # ['旅行', ' エッセイ']

2 つ目の先頭に空白が残っています。このまま数えると エッセイ と エッセイ が別物として扱われ、最初と同じ失敗をやり直すことになります。前後の空白は strip(JavaScript なら trim)で落とします。

区切り文字を ", " にして空白ごと片づけたくなりますが、やめたほうが無難です。"旅行,エッセイ" のように空白なしで入力された行が分けられなくなります。区切るのはカンマだけにして、空白の始末は strip に任せてください。

消し忘れのカンマが、空のタグを作る

人が手で入力した欄には、"旅行, , エッセイ" のように余ったカンマが残っていることがあります。

Python

[raw.strip() for raw in "旅行, , エッセイ".split(",")] # ['旅行', '', 'エッセイ']

真ん中に空文字が残りました。これを出力に入れると、タグ名が空の行が 1 件生まれます。集計では 1 件として数えられ、画面では何も表示されない行になります。strip した結果が空文字なら捨てる、という判定を必ず通してください。

やってみよう

normalize1NF(rows) を完成させてください。rows は [名前, カンマ区切りの文字列] の組の並びで、返すのは 1 値ずつに開いた組の並びです。

  1. 外側で 1 組ずつ取り出し、内側でカンマ区切りを 1 つずつ取り出す
  2. 取り出した値の前後の空白を落とす
  3. 落とした結果が空文字なら、出力に入れない

1 組の入力から複数の組が生まれるので、map だけでは書けません。ループは 2 段になります。

要件

  1. カンマで区切られた文字列を 1 値ずつ分解する
  2. 各値の前後の空白を trim して取り除く
  3. 空文字(trim 後に長さ 0)は出力に含めない

入出力例

normalize1NF([["Alice","reading, music, hiking"],["Bob","gaming"]]) → [["Alice","reading"],["Alice","music"],["Alice","hiking"],["Bob","gaming"]] normalize1NF([["Carol","cooking,travel"]]) → [["Carol","cooking"],["Carol","travel"]] normalize1NF([["Dave"," movies , music "]]) → [["Dave","movies"],["Dave","music"]] normalize1NF([["Eve","art, , drawing"]]) → [["Eve","art"],["Eve","drawing"]] normalize1NF([["A","x,y"],["B","z,w"]]) → [["A","x"],["A","y"],["B","z"],["B","w"]]

ヒント

Python なら `csv.split(',')` の戻り値に対して `for` ループを回す

JavaScript なら `flatMap` と `split(',').map(v => v.trim())` の組み合わせが便利

空文字判定は Python で `if value`、JavaScript で `if (v)` でできる

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

関連レッスン

  • キーで join (map 利用)

    外部キー(foreign key)で 2 つのテーブルを結合する処理を、map(ハッシュテーブル)を使って O(n+m) で実装します。

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

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

  • CAP の availability 模擬

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

  • URL ルーティング

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

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

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

  • データベースデータを構造化して保存する仕組み
  • JavaScriptWeb で動的な振る舞いを担う言語
  • ループ繰り返し処理。矢印で戻すか専用記号で示す
main.py
学習モード
エディタを読み込んでいます

メモ

重複データを 1NF に変換 (フラットなリスト化)

⌘S で保存