[Pythonクイズ]リスト内の要素の重複を削除するなら、for文じゃなくて○○でしょ?Pythonステップアップクイズ

Pythonのリストとfor文の組み合わせってよく見かけます。みんなよくやりますよね。でも、for文と組み合わせなくてもやれることって意外と多いんです。今回はそんな問題。

» 2025年04月08日 05時00分 公開
[かわさきしんじDeep Insider編集部]
「Pythonステップアップクイズ」のインデックス

連載目次

1行で書けるよね? 1行で書けるよね?

【問題】

 以下はリストmylistから重複する要素を取り除いた結果を要素とするリストuniq_listを作成するコードである。ただし、重複する要素を取り除くコードはもっとシンプルに1行で記述できる。どんなコードにすればよいだろうか。ただし、要素の順序については考慮しなくてもよいものとする。

mylist = [6, 9, 9, 9, 6, 9, 7, 1, 9, 8]

uniq_list = []
for num in mylist:
    if num not in uniq_list:
        uniq_list.append(num)
        
print(uniq_list)

重複を取り除くコードを1行で書くにはどうする?

かわさき

 どうもHPかわさきです。

 三寒四温も3月までかと思いきや、4月になっても続いていますねぇ。それでも、筆者のところには「春眠暁を覚えず」の時期がやってまいりました。アラームが1個じゃ足りないので、もう2つくらい設定しないとヤヴァいです。いつも眠いんですけどね。

 それはともかく、リストから重複する要素を取り除く上のコード。分かりやすくてよいと思います。が、とあるデータ構造の特性を知っていると、for文を使わなくてもカンタンに同じことができちゃうんですよね。さて何でしょう?


【答え】

 以下に正解のコード例を示します。

mylist = [6, 9, 9, 9, 6, 9, 7, 1, 9, 8]

uniq_list = list(set(mylist))
        
print(uniq_list)

リストから集合を作成し、それを基にリストを作成するだけ!

 元のリストmylistから集合を作成し、それ基にリストを作成するだけで、重複する要素を排除したリストが得られます。

リストから集合を作成し、それを基にリストを作成するだけ! リストから集合を作成し、それを基にリストを作成するだけ!

【解説】

 ここでおさらいです。集合はリストやタプルと同様に、Pythonに組み込みのコレクションです。その特徴としては次のようなことが挙げられます。

  • 同じ要素が重複することがない
  • 要素はハッシュ可能なものである必要がある
  • 要素は順序を持たない

 これらのことを踏まえて、最初のリストを見てみましょう。

mylist = [6, 9, 9, 9, 6, 9, 7, 1, 9, 8]

uniq_list = []
for num in mylist:
    if num not in uniq_list:
        uniq_list.append(num)
        
print(uniq_list)

問題文のコード

 ちなみにこの実行結果は次のようになります。

実行結果 実行結果

 mylistの要素は、ハッシュ可能な整数値です(hash関数で「ハッシュ値=一種のデータの識別番号」を得られます)。Pythonの集合(set、重複のないデータの集まり)は内部でこのハッシュ値を使って要素を管理しているため、ハッシュ可能な整数値は集合の要素にできるということです。

 そのため、mylistをset関数に渡すと、重複する要素が排除された集合ができます。試してみましょう。

mylist = [6, 9, 9, 9, 6, 9, 7, 1, 9, 8]

s = set(mylist)
print(s)

リストを基に集合を作成

 実行結果は次の通りです。

重複する要素を含まない集合が作成された 重複する要素を含まない集合が作成された

 この通り、重複要素が取り除かれた集合が作成されました。


かわさき

 読者が上のコードを試した場合、集合の要素の並び方が画像に示したものとは異なるかもしれないことには注意してください。これは「集合の要素には順序がない」という性質からくるものです。


 ただし、欲しいのは集合ではなくリストなので、得られた集合からリストを作成する必要があります。このことから、正解例のコードのように集合を作成して、そこからさらにリストを作成するコードを書くことになります。

mylist = [6, 9, 9, 9, 6, 9, 7, 1, 9, 8]

uniq_list = list(set(mylist))
        
print(uniq_list)

リストから集合を作成し、さらにそこからリストを作成する

 実行結果は次のようになります。

問題文のコードとは要素の順序が異なっている 問題文のコードとは要素の順序が異なっている

 これで重複を排除したリストが完成しました。ただし、集合を作成した時点での画像からも分かるように、問題文のコードの実行結果([6, 9, 7, 1, 8]」というリスト)と上のコードの実行結果(「[1, 6, 7, 8, 9]」というリスト)では要素の順序が異なります。順序も考慮したいのであれば、別の方法が必要です。

 その方法とは……別の問題にすることも考えましたが……辞書が持つfromkeysメソッド(クラスメソッド)を使うことです。fromkeysメソッドは反復可能オブジェクトを渡すと、それらをキーとする辞書を作成するものです。キーの値はfromkeysメソッドのvalueパラメーターに指定します(デフォルト引数値はNone)。

 実際のコードは次のようになります。

mylist = [6, 9, 9, 9, 6, 9, 7, 1, 9, 8]

uniq_list = list(dict.fromkeys(mylist))

print(uniq_list)

順序を考慮した場合にはdict.fromkeysメソッドで辞書を作成し、そのキーを使ってリストを作成する

 ここでのポイントは以下の3つです。

  • Python 3.7以降では辞書はキーの挿入順序を覚えている
  • 辞書に1つのキーが複数存在することはない
  • 辞書を単純に反復可能オブジェクトとして使うと、キーが反復される

 mylistには重複する要素が複数あります。そこで、リストの先頭から順番に「リストの要素をキーとして、さらに何らかの値をそのキーの値として」辞書に追加していくことを考えてみましょう。つまり、「6/何らかの値」→「9/何らかの値」→「9/何らかの値」→「9/何らかの値」→……→「9/何らかの値」→「8/何らかの値」という順に辞書に要素を追加していくことを考えてみます。

 1つ目のポイントから、辞書は「リストの要素(キー)/何らかの値」の挿入順序を覚えています。2つ目のポイント「辞書に1つのキーが複数存在することはない」というのは、辞書に何らかのキーが既に存在している場合に、同一のキー/新たな値の組をその辞書に挿入しようとすると、既存のキーの値が新しい値に書き換えられるということです。

 つまり、「9/何らかの値1」という要素を辞書に追加した後に、「9/何らかの値2」という要素を追加しようとすると、既に存在するキー「9」の値が「何らかの値1」から「何らかの値2」に変更されるということです。このときに、キーの順序は以前のままです。そして、ここで「何らかの値」と書いているのは、fromkeysメソッドのvalueパラメーターに指定する値のことで、デフォルトではNoneになります。

 これを踏まえて、問題文にあった元のリストをfromkeysメソッドに渡してみましょう。

mylist = [6, 9, 9, 9, 6, 9, 7, 1, 9, 8]

d = dict.fromkeys(mylist)
print(d)

fromkeysメソッドで辞書を作成すると、リストの要素の順序は維持したまま、重複する要素が単一のキーにまとめられる

 実行結果は次の通りです。

リストの要素をキー、それらの値をNoneとする辞書が作成される リストの要素をキー、それらの値をNoneとする辞書が作成される

 リストの要素から目視で重複要素を取り除いていくと「6→9→7→1→8」となりますが、辞書のキーがこの通りに並んでいることに注目してください。

 また、ポイントの3つ目に挙げたように、辞書を単純に反復可能オブジェクトとして関数などに渡すと、反復されるのはそのキーです。つまり、この辞書をlist関数に渡すと、キーが「6→9→7→1→8」という順番で取り出されてリストの要素になるということです。

uniq_list = list(d)
print(uniq_list)

mylistの要素の順序が維持されたリストが得られる

 実行すると、次のように元のリストであるmylistの要素の順序が維持されたリストが得られます(問題文のコードの実行結果「[6, 9, 7, 1, 8]」と同じ)。

実行結果 実行結果

 まとめると、要素の順序を無視してよければ以下のように集合を作成して、そこからさらにリストを作成します。

mylist = [6, 9, 9, 9, 6, 9, 7, 1, 9, 8]

uniq_list = list(set(mylist))
        
print(uniq_list)

要素の順序を無視してよい場合

 一方、要素の順序が重要な場合は以下のようにfromkeysメソッドで辞書を作成して、そこからさらにリストを作成します。

mylist = [6, 9, 9, 9, 6, 9, 7, 1, 9, 8]

uniq_list = list(dict.fromkeys(mylist))

print(uniq_list)

要素の順序が重要な場合

かわさき

 実はset関数で集合を作る方法も、fromkeysメソッドで辞書を作成する方法もうまくかない場合があります。これについてはまた別の問題として皆さんに見ていただこうと考えています。その日を楽しみにしていてください。

 今回はset関数とlist関数、またはdict.fromkeysメソッドとlist関数を組み合わせるだけだから、そんなに書くことないだろうと予想していたのですが、意外に文量が多くなっちゃいました。少し長い記事なので読んでいると眠くなっちゃうかもしれません。でも、それは春が原因であって、記事のせいじゃないですからね(多分……)。

 あ、忘れていました。集合については「Python入門」の「集合」で、辞書については「辞書」で説明しているので、よろしければそちらもぜひ。


「Pythonステップアップクイズ」のインデックス

Pythonステップアップクイズ

Copyright© Digital Advantage Corp. All Rights Reserved.

スポンサーからのお知らせPR

Deep Insider 髫ェ蛟�スコ荵斟帷ケ晢スウ郢ァ�ュ郢晢スウ郢ァ�ー

隴幢スャ隴鯉ス・隴帷」ッ菫」

注目のテーマ

4AI by @IT - AIを作り、動かし、守り、生かす
Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。