Pythonでデータを扱っていると、リスト(配列)の中に同じ要素が複数含まれてしまう「重複」が発生することがよくあります。
データ分析の前処理や、ユニークな項目だけを抽出したい場合など、この重複した要素を削除したいという場面は非常に頻繁に訪れます。
Pythonには、こうしたリストの重複を削除するための、シンプルで効率的な方法がいくつか用意されています。
しかし、方法によっては元のリストの「順序」が保持されないなど、それぞれに特徴と注意点が存在します。
そこでこの記事では、リスト内で重複している要素を削除する基本的な方法から、多くの開発者が求める「順序を保持したまま」重複を削除する実践的なテクニック、さらには応用編として2次元リストを扱う方法まで、豊富なサンプルコードと共に徹底的に解説していきます。
【本記事の信頼性】
- 執筆者は元エンジニア
- 大手プログラミングスクールのWebディレクター兼ライターを経験
- 自らも地元密着型のプログラミングスクールを運営
受講生から評判の良いプログラミングスクール
スクール |
特徴 |
受講料金 |
大手比較サイトで4年連続人気NO.1!受講生からの評判も非常に高く、Web系のエンジニアを目指すならRUNTEQ一択。 | 550,000円(給付金適用あり) | |
月単価80万円以上の現役エンジニア講師による指導!一度入会すればサポートは半永久的。 | 498,000円 | |
格安で質の高いWeb制作スキルを習得したい人におすすめ!業界最安級の料金でありながら、コミュニティやサポートが充実。 | 129,800円~ | |
完全無料でプログラミングが学べる貴重なスクール!最短1ヶ月で卒業可能。ゼロスク運営会社への就職もできる。 | 無料 | |
長期間に渡って学習し、希少人材を目指す人に最適なスクール!受講料は高いものの、高収入を得られる人材を目指せる。 | 96~132万円 |
【目的別】リストの重複削除 早見表
まず最初に、この記事で解説する主要な重複削除の方法を、目的別にまとめた早見表(チートシート)で示します。あなたの目的に合った方法がすぐに見つかるでしょう。
目的 | 推奨される方法 | 特徴 |
---|---|---|
順序は気にしない、とにかく手早く重複削除したい | set() |
最もシンプルで高速。ただし、元のリストの順序は保持されない。 |
順序を保持したまま重複削除したい(モダンな方法) | dict.fromkeys() |
Python 3.7+で推奨。コードが簡潔で、比較的高速。 |
順序を保持したまま重複削除したい(古典的な方法) | for ループとif 文 |
処理が直感的に分かりやすい。リストが小さい場合は十分実用的。 |
2次元リストなど、複雑な要素の重複を削除したい | for ループとif 文 |
set やdict が使えない場合に有効な、柔軟性の高い方法。 |
set()での重複削除が最も簡単(順序は保持されない)
リストの重複を削除する最もシンプルでPythonicな方法は、set()
関数(集合型)を利用することです。
set
は、数学の「集合」と同じように、「重複した要素を持たない」という性質を持っています。
この性質を利用し、リストを一度set
に変換し、それを再びlist
に戻すだけで、重複する要素がすべて取り除かれます。
サンプルコード
original_list = ['a', 'b', 'c', 'a', 'd', 'b']
# setに変換して重複を削除し、再びlistに戻す
unique_list = list(set(original_list))
print(f"元のリスト: {original_list}")
print(f"重複削除後のリスト: {unique_list}")
実行結果
元のリスト: ['a', 'b', 'c', 'a', 'd', 'b']
重複削除後のリスト: ['d', 'c', 'b', 'a']
注意:実行環境によって、重複削除後のリストの順序は上記と異なる場合があります。
コードの解説
set(original_list)
によって、重複が取り除かれた集合{'a', 'b', 'c', 'd'}
が生成されます。
それをlist()
でリスト型に戻すことで、ユニークな要素だけのリストが完成しました。
最大の注意点 この方法は非常に簡単ですが、見ての通り、元のリストの要素の順序が保持されるかどうかの保証がありません。
set
は順序という概念を持たないデータ構造だからです。
「順序はどうでもいいから、とにかくユニークな値が欲しい」という場合に限定して使用してください。
リスト内の順序を保持したまま重複要素を削除する方法
実務では、「リストの順序は維持したまま、重複だけを取り除きたい」というケースがほとんどです。
この需要に応えるための、より実践的な方法を2つ紹介します。
dict.fromkeys()を使う(モダンで推奨される方法)
Python 3.7以降、辞書(dict)は要素が追加された順序を保持する仕様になりました。
また、辞書のキーは重複を許しません。
この2つの性質を組み合わせたdict.fromkeys()
メソッドが、順序を保持した重複削除のための、現在最も推奨されるエレガントな方法です。
dict.fromkeys()
は、リストなどのイテラブルオブジェクトを引数に渡すと、その要素をキーとする新しい辞書を作成します。
サンプルコード
original_list = ['a', 'b', 'c', 'a', 'd', 'b']
# dict.fromkeys()で順序を保持したまま重複を削除し、listに戻す
unique_list_ordered = list(dict.fromkeys(original_list))
print(f"元のリスト: {original_list}")
print(f"順序を保持して重複削除したリスト: {unique_list_ordered}")
実行結果
元のリスト: ['a', 'b', 'c', 'a', 'd', 'b']
順序を保持して重複削除したリスト: ['a', 'b', 'c', 'd']
コードの解説
dict.fromkeys(original_list)
は、リストの要素を順番にキーとして辞書を生成します。
{'a': None, 'b': None, 'c': None, 'd': None}
のような辞書が作られますが、2回目の'a'
や'b'
はキーとして既に存在するため、無視されます。
この辞書のキーをlist()
でリストに戻すことで、元のリストの出現順を保持したまま、重複が削除されたリストが得られるのです。
forループで地道に処理する(古典的な方法)
set
やdict
の性質を使わずに、for
ループを使って重複削除を実装することも可能です。
処理内容は非常に直感的です。
- 空のリストを用意する。
- 元のリストを先頭から一つずつ見ていく。
- まだ空のリストに含まれていない要素であれば、追加する。
サンプルコード
original_list = ['a', 'b', 'c', 'a', 'd', 'b']
unique_list_loop = []
for item in original_list:
if item not in unique_list_loop:
unique_list_loop.append(item)
print(f"元のリスト: {original_list}")
print(f"forループで重複削除したリスト: {unique_list_loop}")
実行結果
元のリスト: ['a', 'b', 'c', 'a', 'd', 'b']
forループで重複削除したリスト: ['a', 'b', 'c', 'd']
コードの解説
この方法は、処理の流れが分かりやすく、Pythonのバージョンに依存しないというメリットがあります。
ただし、リストのサイズが非常に大きくなると、if item not in ...
のチェック処理に時間がかかり、dict.fromkeys()
に比べてパフォーマンスが低下する可能性があります。
【応用】2次元リスト(リストのリスト)の重複を削除する
[[1, 2], [3, 4], [1, 2]]
のような、リストの中にリストが入っている2次元リストの場合、少し工夫が必要になります。
なぜなら、リストは「ハッシュ化不可能」なオブジェクトであるため、set()
やdict.fromkeys()
に直接渡すとエラーになってしまうからです。
このような場合は、for
ループを使った古典的な方法が有効です。
サンプルコード
matrix = [[10, 20], [30, 40], [10, 20], [50, 60]]
unique_matrix = []
for sublist in matrix:
if sublist not in unique_matrix:
unique_matrix.append(sublist)
print(f"元の2次元リスト: {matrix}")
print(f"重複削除後の2次元リスト: {unique_matrix}")
実行結果
元の2次元リスト: [[10, 20], [30, 40], [10, 20], [50, 60]]
重複削除後の2次元リスト: [[10, 20], [30, 40], [50, 60]]
コードの解説
リスト同士をnot in
で比較することで、内側のリストの内容が同じかどうかを判定し、重複を削除できています。
この方法は、要素がハッシュ化可能かどうかにかかわらず使える、汎用性の高いテクニックです。
パフォーマンスと使い分けの指針
それぞれの方法のパフォーマンスは、リストのサイズや要素の種類によって変動しますが、一般的な傾向は以下の通りです。
- 速度:
set()
>=dict.fromkeys()
>for
ループ - 順序保持:
dict.fromkeys()
=for
ループ >set()
(保持されない)
これらの特性から、以下のような使い分けが推奨されます。
- 順序を気にする必要がなければ、迷わず
set()
を使う。 - 順序を保持したい場合は、
dict.fromkeys()
を第一候補とする。 - 2次元リストなど、ハッシュ化不可能な要素を扱う場合は、
for
ループを使う。
ほとんどの日常的なプログラミングでは、dict.fromkeys()
が最もバランスの取れた選択肢となるでしょう。
まとめ
今回は、Pythonでリスト内の重複した要素を削除するための様々な方法を、それぞれの特徴と共に解説しました。
なお、Pythonを体系的に学んだり、Pythonのスキルを高めたりするためには、プログラミングスクールを利用するのも有効です。
細かな疑問がすぐに解決するだけでなく、現役エンジニアが「質の高いポートフォリオ」を作成するための手助けをしてくれたり、エンジニア就職・転職のコツを教えてくれたりするなど、様々なメリットがありますので、独学に疲れた方は検討してみてはいかがでしょうか。