[解決済み] OrderedDictの先頭に要素を追加するには?
質問
こんなものがあります。
d1 = OrderedDict([('a', '1'), ('b', '2')])
こうすれば
d1.update({'c':'3'})
すると、こうなる。
OrderedDict([('a', '1'), ('b', '2'), ('c', '3')])
が、これが欲しい。
[('c', '3'), ('a', '1'), ('b', '2')]
新しい辞書を作成せずに
どのように解決するのですか?
Python 2にはこれを行うためのビルトインメソッドがありません。これが必要な場合は
prepend()
を操作するメソッド/関数を書く必要があります。
OrderedDict
の内部を O(1) の複雑さで操作するメソッドです。
Python 3.2 以降では
が必要です。
を使用します。
move_to_end
メソッドを使用します。このメソッドでは
last
引数は、要素を一番下に移動させるかどうかを指定します (
last=True
) か、それとも一番上 (
last=False
) の
OrderedDict
.
最後に、もしあなたが迅速で汚い、そして
遅い
解決策としては、単に新しい
OrderedDict
をゼロから作成すればよいのです。
4種類のソリューションの詳細です。
拡張
OrderedDict
を拡張し、新しいインスタンスメソッドを追加します。
from collections import OrderedDict
class MyOrderedDict(OrderedDict):
def prepend(self, key, value, dict_setitem=dict.__setitem__):
root = self._OrderedDict__root
first = root[1]
if key in self:
link = self._OrderedDict__map[key]
link_prev, link_next, _ = link
link_prev[1] = link_next
link_next[0] = link_prev
link[0] = root
link[1] = first
root[1] = first[0] = link
else:
root[1] = first[0] = self._OrderedDict__map[key] = [root, first, key]
dict_setitem(self, key, value)
デモです。
>>> d = MyOrderedDict([('a', '1'), ('b', '2')])
>>> d
MyOrderedDict([('a', '1'), ('b', '2')])
>>> d.prepend('c', 100)
>>> d
MyOrderedDict([('c', 100), ('a', '1'), ('b', '2')])
>>> d.prepend('a', d['a'])
>>> d
MyOrderedDict([('a', '1'), ('c', 100), ('b', '2')])
>>> d.prepend('d', 200)
>>> d
MyOrderedDict([('d', 200), ('a', '1'), ('c', 100), ('b', '2')])
を操作するスタンドアロン関数です。
OrderedDict
オブジェクトを操作するスタンドアロン関数です。
この関数は、dictオブジェクト、キー、値を受け取ることで同じことをします。個人的にはこのクラスの方が好きです。
from collections import OrderedDict
def ordered_dict_prepend(dct, key, value, dict_setitem=dict.__setitem__):
root = dct._OrderedDict__root
first = root[1]
if key in dct:
link = dct._OrderedDict__map[key]
link_prev, link_next, _ = link
link_prev[1] = link_next
link_next[0] = link_prev
link[0] = root
link[1] = first
root[1] = first[0] = link
else:
root[1] = first[0] = dct._OrderedDict__map[key] = [root, first, key]
dict_setitem(dct, key, value)
デモです。
>>> d = OrderedDict([('a', '1'), ('b', '2')])
>>> ordered_dict_prepend(d, 'c', 100)
>>> d
OrderedDict([('c', 100), ('a', '1'), ('b', '2')])
>>> ordered_dict_prepend(d, 'a', d['a'])
>>> d
OrderedDict([('a', '1'), ('c', 100), ('b', '2')])
>>> ordered_dict_prepend(d, 'd', 500)
>>> d
OrderedDict([('d', 500), ('a', '1'), ('c', 100), ('b', '2')])
使用方法
OrderedDict.move_to_end()
(Python >= 3.2)
Python 3.2 の導入
は
OrderedDict.move_to_end()
というメソッドがある。これを使うと、既存のキーを辞書のどちらかの端に O(1) 時間で移動させることができます。
>>> d1 = OrderedDict([('a', '1'), ('b', '2')])
>>> d1.update({'c':'3'})
>>> d1.move_to_end('c', last=False)
>>> d1
OrderedDict([('c', '3'), ('a', '1'), ('b', '2')])
要素を挿入し、それを一番上に移動させる必要がある場合、すべて一度に、直接
prepend()
ラッパーを使用することができます(ここでは紹介しません)。
新規に作成する
OrderedDict
- 遅い!!!
それが嫌な方や パフォーマンスが問題でない場合 であれば、最も簡単な方法は新しいdictを作成することです。
from itertools import chain, ifilterfalse
from collections import OrderedDict
def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in ifilterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
d1 = OrderedDict([('a', '1'), ('b', '2'),('c', 4)])
d2 = OrderedDict([('c', 3), ('e', 5)]) #dict containing items to be added at the front
new_dic = OrderedDict((k, d2.get(k, d1.get(k))) for k in \
unique_everseen(chain(d2, d1)))
print new_dic
を出力します。
OrderedDict([('c', 3), ('e', 5), ('a', '1'), ('b', '2')])
関連
-
[解決済み] for'ループでインデックスにアクセスする?
-
[解決済み] リストのリストからフラットなリストを作るには?
-
[解決済み] 辞書を値で並べ替えるにはどうしたらいいですか?
-
[解決済み] Pythonで辞書に新しいキーを追加するにはどうすればよいですか?
-
[解決済み] PandasでDataFrameの行を反復処理する方法
-
[解決済み] バイトを文字列に変換する
-
[解決済み】Pythonで辞書のキーをリストとして返すには?
-
[解決済み】2つの辞書を1つの式でマージする(辞書の和をとる)には?)
-
[解決済み] Cythonのコードを含むPythonパッケージはどのように構成すればよいのでしょうか?
-
[解決済み] Pythonの辞書にあるスレッドセーフについて
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 2つの線分が交差しているかどうかを確認するにはどうすればよいですか?
-
[解決済み] PythonでファイルのMD5チェックサムを計算するには?重複
-
[解決済み] pandasのDataFrameから空のセルを含む行を削除する
-
[解決済み] googletransがエラー 'NoneType' オブジェクトに 'group' 属性がない、と言って動かなくなった。
-
[解決済み] django.db.migrations.exceptions.InconsistentMigrationHistory
-
[解決済み] 小数点以下1桁を取得する[重複]。
-
[解決済み] Pythonのargparseを使った隠し引数の作成
-
[解決済み] pandasのタイムゾーンに対応したDateTimeIndexを、特定のタイムゾーンに対応したナイーブなタイムスタンプに変換する。
-
[解決済み] Celeryタスクのユニットテストはどのように行うのですか?
-
[解決済み] Python 言語を決定するには?