web-dev-qa-db-ja.com

Python 3.6+での位置による辞書項目への効率的なアクセス

辞書は 挿入順序Python 3.6 + 、3.6の実装の詳細および3.7+の公式として)であることを理解しています。

それらが順序付けられているとすると、iを取得するメソッドが存在しないのは奇妙に思えます番目 挿入順による辞書の項目。 ソリューションのみ が利用可能な場合、O(n)の複雑さがあるように見えます。

  1. O(n)プロセスを介してリストに変換し、list.__getitem__
  2. ループ内のenumerate辞書項目。目的のインデックスに到達したときに値を返します。繰り返しますが、O(n)時間の複雑さです。

listから項目を取得するとO(1)複雑さを持っているため、辞書で同じ複雑さを達成する方法はありますか?通常のdictまたはcollections.OrderedDict動作します。

それが不可能な場合、そのような方法を妨げる構造的な理由がありますか、またはこれはまだ考慮/実装されていない機能ですか?

26
jpp

OrderedDictの場合、順序は リンクリスト に記録されるため、本質的にO(n)です。

組み込みの辞書には、リンクされたリストではなくベクトル(連続した配列)がありますが、最終的にはほぼ同じです。ベクトルには、「キーがありません」という特別な内部値が含まれています。 「ここにまだ保存されている」または「ここに保存されていたが、もはや存在しないキー」。これにより、たとえば、キーを非常に安価に削除できます(キーをダミー値で上書きするだけです)。

しかし、その上に補助データ構造を追加しないと、ダミーを1つずつ行かないでスキップする方法はありません。 Pythonは衝突解決にオープンアドレッシングの形式を使用し、負荷係数を2/3未満に保つため、ベクトルのエントリの少なくとも3分の1areダミー_the_vector[i]_はO(1)時間でアクセスできますが、実際にはi番目の非ダミーエントリと予測可能な関係はありません。

36
Tim Peters

@ TimPeters 'answer に従って、O(1)時間内の位置によって辞書項目にアクセスできない構造上の理由があります。

O(1)キーによる検索または位置を探している場合は、代替案を検討する価値があります。NumPy/ Pandasこのような機能を提供します。効率的です特にポインターが不要な数値配列の場合。

Pandasを使用すると、O(1)「ラベル」または位置によるルックアップを提供するユニークなラベルを使用して、「辞書のような」シリーズを構築できます。 O(n)コスト、listによく似ています。

import pandas as pd

s = pd.Series(list(range(n)))

# O(n) item deletion
del s[i]
s.drop(i)
s.pop(i)

# O(1) lookup by label
s.loc[i]
s.at[i]
s.get(i)
s[i]

# O(1) lookup by position
s.iloc[i]
s.iat[i]

pd.Seriesは、dictのドロップイン置換ではありません。たとえば、シリーズが主にマッピングとして使用される場合、重複キーは防止されず、問題が発生します。ただし、上記の例のように、データが連続したメモリブロックに格納されている場合、パフォーマンスが大幅に向上する場合があります。

こちらもご覧ください:

  1. NumPyの通常のPythonリストと比べて)の利点は何ですか?
  2. pandasの非一意インデックスのパフォーマンスへの影響は?
  3. Pandas DataFrame検索は線形時間ですか、それとも一定時間ですか?
3
jpp