Pythonでリスト(配列)に重複した要素があるか判定

Modified: | Tags: Python, リスト

Pythonで、リスト(配列)に重複した要素があるか(すべての要素が一意・ユニークであるか)を判定する方法について説明する。

リストから重複した要素を削除したり抽出したりする方法は以下の記事を参照。

なお、リストは異なる型のデータを格納可能で、厳密には配列とは異なる。配列を扱いたい場合はarray(標準ライブラリ)やNumPyを使う。

リストに重複した要素があるか判定(要素にリストがない場合)

要素にリストなどの更新可能なオブジェクトがない場合は、集合set型のコンストラクタset()を使う。

set型は重複した要素をもたないデータ型で、コンストラクタset()にリストを渡すと、重複する値は無視されて一意な値のみが要素となるset型のオブジェクトを返す。

このset型のオブジェクトと元のリストの要素数を組み込み関数len()で取得し比較する。要素数が等しければ元のリストに重複した要素はなく、要素数が異なっていれば元のリストに重複した要素が含まれている。

重複した要素がないときはFalse、重複した要素があるときはTrueを返す関数は以下の通り。

def has_duplicates(seq):
    return len(seq) != len(set(seq))

l = [0, 1, 2]
print(has_duplicates(l))
# False

l = [0, 1, 1, 2]
print(has_duplicates(l))
# True

例はリストだが、タプルでも同じ関数が使える。

リストなどのミュータブル(更新可能)なオブジェクトはset型の要素にできないため、要素にリストを持つリスト(二次元配列、リストのリストなど)の場合はエラーTypeErrorになる。対応策は次に示す。

l_2d = [[0, 1], [1, 1], [0, 1], [1, 0]]
# print(has_duplicates(l_2d))
# TypeError: unhashable type: 'list'

リストに重複した要素があるか判定(要素にリストがある場合)

要素にリストを持つリスト(リストのリストなど)の場合、以下のような関数で重複した要素があるかを判定できる。

def has_duplicates2(seq):
    seen = []
    unique_list = [x for x in seq if x not in seen and not seen.append(x)]
    return len(seq) != len(unique_list)

l_2d = [[0, 0], [0, 1], [1, 1], [1, 0]]
print(has_duplicates2(l_2d))
# False

l_2d = [[0, 0], [0, 1], [1, 1], [1, 1]]
print(has_duplicates2(l_2d))
# True

set()ではなくリスト内包表記で一意な値のみが要素となるリストを生成し、要素数を比較している。詳細は以下の記事を参照。

この関数は要素にリストを持たないリストに対しても有効。

l = [0, 1, 2]
print(has_duplicates2(l))
# False

l = [0, 1, 1, 2]
print(has_duplicates2(l))
# True

これまでの例は、要素のリストが重複しているかどうか(同じリストが含まれているか)の判定。

各リストの要素が重複しているかどうかは元のリストを一次元に平坦化してから判定すればよい。

l_2d = [[0, 1], [2, 3]]
print(sum(l_2d, []))
# [0, 1, 2, 3]

print(has_duplicates(sum(l_2d, [])))
# False

l_2d = [[0, 1], [2, 0]]
print(has_duplicates(sum(l_2d, [])))
# True

ここではリストの平坦化にsum()を使っているがitertools.chain.from_iterable()を使う方法もある。また、3次元以上のリストを平坦化する場合は新たに関数を定義する必要がある。以下の記事を参照。

関連カテゴリー

関連記事