中学理科1630641 views
中学英語811710 views
雑学1473612 views
いろは3010814 views
LaTeX962153 views
小学算数1200427 views
世界の国564520 views
ヒストリア290598 views
高校倫理1440106 views
高校日本史190571 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 vs list(いつ集合を使うべきか)

set と list は Python でよく使われるコレクション型だが、特性が大きく異なる。適切に使い分けることで、パフォーマンスとコードの明確さが向上する。

基本的な特性の違い

両者の根本的な違いを整理する。

list

順序あり、重複あり、インデックスアクセス可能、ミュータブル

set

順序なし、重複なし、インデックスアクセス不可、ミュータブル

この違いがすべての判断基準になる。

検索パフォーマンス

要素の存在確認は、set が圧倒的に高速だ。

import time

n = 100000
items_list = list(range(n))
items_set = set(range(n))

# list での検索
start = time.perf_counter()
for i in range(1000):
    99999 in items_list
print(f"list: {time.perf_counter() - start:.4f}s")

# set での検索
start = time.perf_counter()
for i in range(1000):
    99999 in items_set
print(f"set: {time.perf_counter() - start:.4f}s")

list は O(n)、set は O(1) なので、要素数が増えるほど差は顕著になる。

要素数listset
1,0000.01秒0.0001秒
100,0001秒0.0001秒
1,000,00010秒0.0001秒

存在確認が頻繁に必要なら、迷わず set を選ぶべきだ。

順序が必要な場合

要素の順序を維持する必要があるなら list を使う。

# 順序が意味を持つデータ
steps = ["mix", "bake", "cool", "decorate"]
for i, step in enumerate(steps, 1):
    print(f"{i}. {step}")

set では挿入順序が保証されない(Python 3.7 以降も保証されていない)。

s = set()
s.add("a")
s.add("b")
s.add("c")
print(list(s))  # 順序は不定

インデックスアクセス

list は位置によるアクセスが可能だが、set はできない。

items = [10, 20, 30, 40, 50]
print(items[0])   # 10
print(items[-1])  # 50
print(items[1:3]) # [20, 30]

s = {10, 20, 30, 40, 50}
# s[0]  # TypeError: 'set' object is not subscriptable

特定の位置にある要素を取得したいなら list が必須だ。

重複の扱い

list は同じ値を複数持てるが、set は自動的に重複を排除する。

# 重複を許容したい場合
votes = ["A", "B", "A", "A", "B", "C"]
print(votes.count("A"))  # 3

# 重複を排除したい場合
unique_votes = set(votes)
print(unique_votes)  # {'A', 'B', 'C'}

投票の集計など、重複が意味を持つ場合は list を使う。

メモリ使用量

同じ要素数でも、set のほうがメモリを多く消費する。

import sys

n = 1000
items_list = list(range(n))
items_set = set(range(n))

print(f"list: {sys.getsizeof(items_list):,} bytes")  # 8,856 bytes
print(f"set: {sys.getsizeof(items_set):,} bytes")    # 32,984 bytes

set はハッシュテーブルを維持するため、オーバーヘッドが大きい。メモリ制約がある環境では考慮が必要だ。

追加操作のパフォーマンス

末尾への追加は両者とも高速だ。

# list の append: O(1) 償却
items = []
for i in range(100000):
    items.append(i)

# set の add: O(1) 平均
items = set()
for i in range(100000):
    items.add(i)

ただし、list は先頭への挿入が O(n) になる。

items = list(range(10000))

# 先頭への挿入は遅い
items.insert(0, -1)  # O(n)

# set には順序がないので「先頭」の概念がない

使い分けの判断基準

set を選ぶ場面

要素の存在確認が頻繁にある。重複を排除したい。集合演算(和集合・積集合など)を行う。

list を選ぶ場面

順序が重要。インデックスアクセスが必要。重複を保持したい。スライス操作を使う。

典型的な使用パターン

存在確認が必要なデータは set で持つ。

# 許可されたユーザー ID(検索が頻繁)
allowed_users = {"user123", "user456", "user789"}

def is_allowed(user_id):
    return user_id in allowed_users

順序が重要なデータは list で持つ。

# 処理のキュー(順序が重要)
task_queue = ["task1", "task2", "task3"]

def process_next():
    if task_queue:
        return task_queue.pop(0)

両方の特性が必要なら、両方を持つこともある。

class OrderedUniqueCollection:
    def __init__(self):
        self._list = []
        self._set = set()
    
    def add(self, item):
        if item not in self._set:
            self._list.append(item)
            self._set.add(item)
    
    def __contains__(self, item):
        return item in self._set  # O(1)
    
    def __iter__(self):
        return iter(self._list)  # 順序を保持

変換のコスト

list と set の相互変換にはコストがかかる。

import time

items = list(range(100000))

# list → set: O(n)
start = time.perf_counter()
s = set(items)
print(f"list to set: {time.perf_counter() - start:.4f}s")

# set → list: O(n)
start = time.perf_counter()
l = list(s)
print(f"set to list: {time.perf_counter() - start:.4f}s")

頻繁に変換が必要なら、最初から適切な型を選ぶほうがよい。検索が多いなら set、順序操作が多いなら list で持ち続ける設計を心がけるべきだ。