Добавить ключи в словарь в отсортированном порядке

Предположим, у меня есть словарь

{1:5, 2:5, 4:5}

есть ли структура данных такая, что если я добавлю пару ключ-значение 3:5, чтобы он был введен в словарь, чтобы ключи были в отсортированном порядке? т. е.

{1:5, 2:5, 3:5, 4:5}

Я в курсе collections.OrderedDict(), но это только сохраняет ключи в том порядке, в котором они были добавлены (что для меня в настоящее время недостаточно).

Я не хочу использовать обычный словарь dic = {}, тогда придется использовать sorted(dic)[0] хапнуть ключик. Я бы предпочел sorted_dict[0] тип функции.
Причина этого в том, что если я использую обычный словарь, мне придется вызывать сортировку несколько раз, так как я постоянно добавляю пары в свой словарь.

EDIT: я должен был упомянуть, что это не только самые маленькие и самые большие ключи, о которых я забочусь, мне также нужно будет печатать этот словарь через регулярные промежутки времени...

3 ответов


если вы планируете добавлять и удалять ключи из словаря непрерывно, вы действительно хотите что-то, что использует соответствующую структуру данных для проблемы-не хэш-таблицу (или хэш-таблицу плюс список, как с SortedOrderedDict-Type recipes), но сбалансированное дерево (или эквивалент, например, список пропусков).

если вы посмотрите на PyPI, вы найдете несколько вариантов. Моя рекомендация была бы blist. Даже если его структура данных может быть не совсем оптимальной как и некоторые другие (потому что дерево B+намного шире, чем двоичное дерево), оно, вероятно, достаточно хорошо для почти любого случая использования, с которым вы столкнетесь. И он имеет полный и хорошо протестированный интерфейс, включая хорошо протестированные гарантии производительности. И он довольно часто используется в других серьезных проектах.

если вы имеете дело с одним из редких случаев, когда производительность дерева действительно критична, вы, вероятно, должны посмотреть на различные красно-черное дерево, splay tree, skiplist и т. д. реализации. Я использовал bintrees раньше, который имеет отличный интерфейс (например, вы можете получить доступ к ключам и значениям по индексу и даже нарезать дерево, а также рассматривать его как dict, и автор продумал и избежал всех потенциальных двусмысленностей), но я серьезно не тестировал его производительность.

или, если ваши ключи и значения действительно являются мелкими целыми числами, вы можете рассмотреть возможность использования Cython для обертывания c++ map<int, int> в Pythonic взаимодействие. (Это не совсем возможно, чтобы обеспечить полное интерфейс поверх C++ map, но часто это не нужно в любом случае.) Или, альтернативно, измените одну из реализаций, таких как bintrees.FastRBTree для хранения и сравнения long вместо PyObject*.

С другой стороны, если вы только собираетесь создать словарь всех сразу, а затем использовать его, есть гораздо более простой ответ. Сортируйте его и вставляйте в OrderedDict. Тогда вам не нужно ничего за пределами stdlib.

sorted_dict = collections.OrderedDict(sorted(d.iteritems()))

из комментария к другому ответу вы говорите: "у меня нет разрешений на установку новых модулей..."

во-первых, убедитесь, что это действительно правда. Вы, вероятно, do есть разрешение на установку модулей в каталоге сайта пользователя-пакеты. Или, если и/или вы используете 3.3 со встроенным venv, еще лучше, у вас, вероятно, есть разрешение на создание venv и установку модулей в это.

но если Итак, что вам нужно сделать, это скопировать файлы из blist/bintrees / что угодно в ваш проект.

проблема, с которой вы можете столкнуться, заключается в том, что большинство этих пакетов содержат модули расширения C, что означает, что вы должны иметь возможность их создавать (ну,build_ext -i них). Если в вашей системе нет файлов python dev и цепочки инструментов компилятора, вы не можете этого сделать. В этом случае вы ищете лучшее решение pure-Python. bintrees поставляется с реализацией pure-Python, которая идентично обычной реализации C-extension, за исключением более медленного. Это все еще O(log N), конечно, просто постоянный фактор намного выше. Если N достаточно большой, это все еще огромная победа; если нет, это может быть не так.

если какая-либо часть этого звучит разумно, но вам нужна помощь в настройке пакетов сайта для каждого пользователя или виртуального env, или копировании модуля в проект на месте, или создании расширений на месте и т. д., вы, вероятно, должны искать существующие вопросы и задавать новые, если вы не могу найти его (хотя бы потому, что люди, которые являются экспертами по вопросам установки, не обязательно являются экспертами в структурах данных и даже не могут читать этот вопрос).


попробуйте этот рецепт - http://code.activestate.com/recipes/576998-sorted-dictionary/

Он сохраняет ключи, отсортированные с помощью stdlib bisect модуль.


более чем на год опоздал на вечеринку, но я хотел предложить sortedcontainers модуль. Как blist и bintrees, он обеспечивает SortedDict тип данных, который хранит ключи в отсортированном порядке. В отличие от этих модулей он написан на чистом Python и на самом деле быстрее. SortedDict также поддерживает индексирование. Поиск min / max фактически происходит в O (1) раз.

поскольку это pure-Python, установка с pip должна быть Бриз:

pip install sortedcontainers

тогда вы можете просто импортировать SortedDict

In [1]: from sortedcontainers import SortedDict

In [2]: d = SortedDict({1:5, 2:5, 4:5})

In [3]: d
Out[3]: SortedDict({1: 5, 2: 5, 4: 5})

In [4]: d[3] = 5

In [5]: d
Out[5]: SortedDict({1: 5, 2: 5, 3: 5, 4: 5})

Если у вас возникли трудности с установкой вещей с помощью pip или не удается скопировать файлы, которые будут нуждаться в компиляции, то вы можете просто вытащить sortedlist.py и sorteddict.py файлы из хранилища. Весь код С открытым исходным кодом на github.

модуль sortedcontainers также предоставляет сравнение производительности С самыми популярными предложениями benchmarked против одного другой.