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次元以上のリストを平坦化する場合は新たに関数を定義する必要がある。以下の記事を参照。