高校国語788336 views
教育149510 views
小学算数1200427 views
りんご209490 views
高校日本史190571 views
LaTeX962153 views
中学英語811710 views
小学社会310485 views
中学理科1630641 views
高校生物551766 views
Help
Tools
NewsSpreadsheetCalendarSlidesTier ListPen ToolIllustrationCrayonPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsCross SectionsMotion PathMechanicsWavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic Theory

English

Python の集合を使った重複排除パターン

集合は重複を自動的に排除するため、データのユニーク化に最適だ。ここでは様々な重複排除パターンを紹介する。

基本的な重複排除

リストから重複を除去する最もシンプルな方法は、set に変換することだ。

items = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique = list(set(items))
print(unique)  # [1, 2, 3, 4](順序は不定)

ただし、この方法では元の順序が失われる。順序を保持したい場合は別のアプローチが必要だ。

順序を保持した重複排除

Python 3.7 以降は dict が挿入順序を保持するため、これを利用できる。

items = [3, 1, 2, 1, 3, 2, 4]
unique = list(dict.fromkeys(items))
print(unique)  # [3, 1, 2, 4](出現順を保持)

dict.fromkeys() は各要素をキーとする辞書を作る。重複するキーは無視されるため、最初に出現した順序が保たれる。

set を使用

順序が失われる。最もシンプル。

dict.fromkeys を使用

順序を保持。Python 3.7 以降で確実。

ループで実装する方法

見たことのある要素を set で追跡しながら、新しい要素だけを追加するパターンもある。

def unique_ordered(items):
    seen = set()
    result = []
    for item in items:
        if item not in seen:
            seen.add(item)
            result.append(item)
    return result

items = [3, 1, 2, 1, 3, 2, 4]
print(unique_ordered(items))  # [3, 1, 2, 4]

この方法は、途中で処理を挟みたい場合に柔軟性がある。

条件付き重複排除

特定の条件に基づいて重複を判定したい場合がある。例えば、辞書のリストから特定のキーで重複を排除する。

users = [
    {"id": 1, "name": "Alice"},
    {"id": 2, "name": "Bob"},
    {"id": 1, "name": "Alice (duplicate)"},
    {"id": 3, "name": "Charlie"},
]

seen_ids = set()
unique_users = []
for user in users:
    if user["id"] not in seen_ids:
        seen_ids.add(user["id"])
        unique_users.append(user)

print(unique_users)
# [{'id': 1, 'name': 'Alice'}, {'id': 2, 'name': 'Bob'}, {'id': 3, 'name': 'Charlie'}]

id が重複する 2 番目の Alice は除外される。

オブジェクトの属性で重複排除

カスタムオブジェクトの場合、特定の属性を基準にできる。

from dataclasses import dataclass

@dataclass
class Product:
    sku: str
    name: str
    price: int

products = [
    Product("A001", "Apple", 100),
    Product("B002", "Banana", 80),
    Product("A001", "Apple (old)", 90),
    Product("C003", "Cherry", 150),
]

seen_skus = set()
unique_products = []
for p in products:
    if p.sku not in seen_skus:
        seen_skus.add(p.sku)
        unique_products.append(p)

print([p.name for p in unique_products])
# ['Apple', 'Banana', 'Cherry']

関数化して汎用的に

キー関数を受け取る汎用的な重複排除関数を作ると便利だ。

def unique_by(items, key=None):
    seen = set()
    result = []
    for item in items:
        k = key(item) if key else item
        if k not in seen:
            seen.add(k)
            result.append(item)
    return result

# 使用例
words = ["Apple", "APPLE", "apple", "Banana", "BANANA"]
unique = unique_by(words, key=str.lower)
print(unique)  # ['Apple', 'Banana']

大文字小文字を無視した重複排除ができる。

複数のキーで重複判定

複数の属性を組み合わせて重複を判定する場合は、タプルをキーにする。

records = [
    {"date": "2024-01-01", "user": "alice", "action": "login"},
    {"date": "2024-01-01", "user": "bob", "action": "login"},
    {"date": "2024-01-01", "user": "alice", "action": "login"},
    {"date": "2024-01-02", "user": "alice", "action": "login"},
]

seen = set()
unique = []
for r in records:
    key = (r["date"], r["user"])
    if key not in seen:
        seen.add(key)
        unique.append(r)

print(len(unique))  # 3

同じ日に同じユーザーが複数回ログインした記録は 1 つにまとめられる。

ジェネレータ版

メモリ効率を重視する場合、ジェネレータで実装できる。

def unique_gen(items, key=None):
    seen = set()
    for item in items:
        k = key(item) if key else item
        if k not in seen:
            seen.add(k)
            yield item

# 大量のデータでもメモリ効率がよい
for item in unique_gen(range(1000000)):
    pass  # 結果を一度に保持しない

結果を一度にリスト化せず、順次処理する場合に有効だ。

最後に出現した要素を残す

通常は最初に出現した要素を残すが、最後を残したい場合もある。

items = [1, 2, 1, 3, 2, 4, 3]

# 最後に出現した要素を残す
result = list(dict.fromkeys(reversed(items)))[::-1]
print(result)  # [1, 4, 2, 3]

リストを反転してから処理し、結果を再度反転する。

pandas での重複排除

pandas を使う場合は drop_duplicates() が便利だ。

import pandas as pd

df = pd.DataFrame({
    "id": [1, 2, 1, 3, 2],
    "name": ["A", "B", "A", "C", "B"]
})

# id で重複排除(最初を残す)
unique_df = df.drop_duplicates(subset=["id"], keep="first")
print(unique_df)

大規模データの処理では pandas のほうが高速な場合がある。

パフォーマンス比較

各方法のパフォーマンスを比較する。

import time

items = list(range(10000)) * 10  # 10万要素、重複あり

# set 変換
start = time.perf_counter()
result = list(set(items))
print(f"set: {time.perf_counter() - start:.4f}s")

# dict.fromkeys
start = time.perf_counter()
result = list(dict.fromkeys(items))
print(f"dict.fromkeys: {time.perf_counter() - start:.4f}s")

# ループ版
start = time.perf_counter()
seen = set()
result = [x for x in items if not (x in seen or seen.add(x))]
print(f"loop: {time.perf_counter() - start:.4f}s")

set() が最速だが、順序保持が必要なら dict.fromkeys() が良いバランスだ。