【初心者向け】Pythonで重複行削除ツールを作ろう!|Python100本ノック Lesson 19

Pythonで学べる100のミニアプリ ロードマップ

はじめに

第18回では フォルダ内のファイル一覧表示 を作って、pathlib でファイル情報を扱ったな。
今回はテキスト整形の定番ワーク、「重複行削除ツール」 に挑戦しよう!

ログや名簿、タグ一覧など、同じ行が紛れ込む問題はよくある。
重複を取り除き、最初の順序を保ったまま きれいに整える実用ツールを作るで。


完成イメージ

names.txt(入力)

Alice
Bob
Alice
Charlie
Bob

プログラム実行後の unique.txt(出力)

Alice
Bob
Charlie

ヒント(使う要素)

  • with open(..., "r") / "w":ファイル読み書き
  • set():すでに見た行の管理に便利
  • 順序保持set だけでなく、最初の出現順を維持するロジックがコツ
  • strip():末尾の改行や余分な空白の扱いをそろえる

コード全文(基本版:順序保持)
まずは最初に出てきた順番を維持しながら、完全一致の重複を消す最小構成や。
# Lesson 19: 重複行削除ツール(基本版:順序保持)

src = "names.txt"     # 入力ファイル
dst = "unique.txt"    # 出力ファイル

seen = set()
unique_lines = []

with open(src, "r", encoding="utf-8") as f:
    for line in f:
        line = line.rstrip("\n")  # 改行のみ除去(空白は保持)
        if line not in seen:
            seen.add(line)
            unique_lines.append(line)

with open(dst, "w", encoding="utf-8") as f:
    for line in unique_lines:
        f.write(line + "\n")

print(f"重複を削除しました:{src} → {dst}")
print(f"元の行数:{len(seen) + (len(unique_lines) - len(seen))} / ユニーク行数:{len(unique_lines)}")

ポイント

  • rstrip("\n")改行だけ落とし、行頭・行末の空白は保持(厳密一致)。
  • 順序は unique_lines の積み上げ順で維持される。

改良版1:空白・大文字小文字を無視して判定
データの“ゆらぎ”をならしたいときは、比較キーを作って判定用に使う。
# Lesson 19: 重複行削除ツール(改良版:空白・大文字小文字を無視)

src = "names.txt"
dst = "unique_normalized.txt"

def norm(s: str) -> str:
    # 先頭末尾の空白を除去し、小文字化して比較キーを作る
    return s.strip().lower()

seen = set()
unique_lines = []

with open(src, "r", encoding="utf-8") as f:
    for raw in f:
        raw = raw.rstrip("\n")
        key = norm(raw)
        if key not in seen:
            seen.add(key)
            # 保存は“元の表示”を優先:raw を書き出す
            unique_lines.append(raw)

with open(dst, "w", encoding="utf-8") as f:
    for line in unique_lines:
        f.write(line + "\n")

print(f"重複(空白・大小無視)を削除しました:{src} → {dst}")


改良版2:削除数のレポート & 回数集計も出力
どの行が何回出てきたかを知れると、データクレンジングに役立つで。
# Lesson 19: 重複行削除ツール(改良版:回数集計 & レポート)

from collections import Counter

src = "names.txt"
dst = "unique_with_report.txt"
report = "duplicates_report.txt"

lines = []
with open(src, "r", encoding="utf-8") as f:
    for line in f:
        lines.append(line.rstrip("\n"))

# 完全一致でカウント
cnt = Counter(lines)

# 順序保持のユニーク
seen = set()
unique_lines = []
for line in lines:
    if line not in seen:
        seen.add(line)
        unique_lines.append(line)

# 出力
with open(dst, "w", encoding="utf-8") as f:
    for line in unique_lines:
        f.write(line + "\n")

# レポート出力(2回以上出現した行を列挙)
with open(report, "w", encoding="utf-8") as r:
    r.write("--- 重複行レポート ---\n")
    total_dups = 0
    for line, c in cnt.items():
        if c > 1:
            r.write(f"{line} : {c} 回\n")
            total_dups += c - 1
    r.write(f"\n削除された重複行の合計:{total_dups}\n")

print(f"ユニーク出力:{dst} / レポート:{report}")


実行方法

  1. 対象テキスト(例:names.txt)を用意
  2. いずれかのコードを lesson19.py として保存
  3. ターミナルで実行: python lesson19.py (動かへん場合は python3 lesson19.py

応用アイデア

  • 巨大ファイル対応:行ごとに処理して逐次書き込み(メモリ節約)
  • GUI化tkinter.filedialog.askopenfilename() でファイル選択
  • CSV向け:列を指定して重複判定(例:メールアドレス列のみ)
  • 正規化戦略切替:厳密一致/空白無視/記号除去などをオプション化

まとめ

今回は 重複行削除ツール を作ったで!
set順序保持の発想、そして正規化キーを使うテクニックを押さえれば、
現場で“使える”データクレンジングが一気に進むんや。

👉 次回は Lesson 20: ファイル拡張子一括変換ツール
画像やテキストの拡張子をまとめて変換する、地味に便利なアプリを作るで!