順序付きセットと順序なしセットの違いを理解しています。また、多くの目的で順序付きセットが必要ない理由を理解しています。しかし、すべてのセット操作は順序付けられたセットでも可能であり、セットは何らかの順序で内部的に保存する必要があるので、なぜデフォルトでセットが順序付けされていないのですか?セットの順序を保持することによるパフォーマンスへの影響は大きすぎますか?
重要なのは、オーバーヘッドが特に大きいということではなく、それが存在することよりも---まったくです。
言語機能は常に費用対効果のバランスをとらなければなりません。辞書はPythonプログラミングの絶対不可欠な要素であるため、ほとんどの場合、挿入順序を維持するために必要な場合よりも少し遅くなることは非常に悪いでしょう。順序付けが必要です。わずかに高速なアクセスのために挿入順序を破棄し、特別なクラスに順序を維持するデータ構造を残すことは正しい決定でした。dictでできることをすべて実行できる別のデータ構造があり、dictが使用頻度の低い言語のしわにより、状況が異なる場合があります。
あなたは正しいですが、アイテムは何らかの順序で内部に保存されますが、この内部順序はキーのハッシュコードによって決定されるため、非常に高速に検索できます。したがって、セット/ディクショナリを順序付けする必要がある場合、これのために別個の内部データ構造(たとえば、キーの順序付けられたリスト)を維持する必要があります。
これはもちろんサイズを増やします。しかし、おそらくもっと悪いことに、それはパフォーマンスに影響を与えます。たとえば、セットから項目を削除することはO(1)操作ですが、内部の順序付きリストからキーを削除する必要がある場合、O(n)になります。このようなコスト順序付けされたセットが必要になることは非常にまれであることを考えると、このようなトレードオフは、標準のセット/ dictタイプでは価値がありません。
あなたの前提は間違っています。 Python 3.6、 dict
s覚えている挿入順序 現在、これは実装の詳細であり、3.7で完全な言語機能に昇格しました。3.6では、 、**kwargs
の特定のケースでは、順序の維持が特に保証されます。
順序付けされたセットは、格納される要素が最初に順序付け(つまり、比較メソッド)を持っている場合にのみ可能ですが、常に指定されているとは限りません。
最近のほとんどの環境でのデフォルトのセット/マップの実装は、自動サイズ変更ハッシュテーブルに基づいています。これには次の利点があります。
セットはとにかくいくつかの順序で内部的に保存する必要があります
しかし、この内部秩序は必ずしも意味を持たず、同じままではありません。実際、経験の浅い開発者を混乱させることがあるハッシュテーブルの1つの特性は、内部の順序に基づいてisである反復順序が、要素が追加されたとき(つまり、サイズ変更がトリガーされたとき)または異なる間で完全に変わる可能性があることです。実行します。
セットまたはディクショナリの背後にある一般的な考え方は、多くのルックアップ操作を実行することを計画しているということです。ほとんどの場合O(1)ルックアップを許可するハッシュを使用することにより、上記のルックアップ操作用に最適化されています。
順序付けは、配列またはリンクリストを使用して行われ、実際には順序が重要な操作を実行します。これらは、末尾または先頭に値を追加するなど、thatに対して最適化されています。
これら2つのデータ構造の性質上、どちらも両方に最適化されていません。これは不可能ではありませんが、ルックアップと順序ベースの操作の両方を最適化したい場合は、両方のデータ構造が関係します。
したがって、次のようなトレードオフがあります。
ルックアップ操作の最適化<=>順序ベースの操作<=>メモリ使用量
一般的なコンセンサスは、プログラマーとして一般的にどちらか一方だけを最適化することですが、どちらか一方のみを最適化する必要があるときに、メモリ使用量を2倍にすることを主張する人はいません。
とはいえ、両方、または少なくともJavaでの実装はあるであり、具体的にはLinkedHashMap
は配列であり、ハッシュベースの辞書でもあります。両方が必要になることもありますが、リストだけが必要な場合はArrayList
を、辞書だけが必要な場合はHashMap
を使用することをお勧めします。