LINUX.ORG.RU

питонистам


0

0

как в питоне организовать сортированный хеш?
например листинг директории -- набор объектов с аттрибутами filename, size, owner,..., из которого можно получать объекты по имени, но при итерации чтобы объекты также были упорядочены.

насколько помню, dict никакого порядка элементов не гарантирует; сортировать ключи всякий раз перед итерацией тоже неохота.
существует ли простой и красивый выход?

anonymous

Эээ.... привыкнуть надо. В общем да, это неудобно. Если бы приперло я б сваял что нить вроде:

class sort_dict(dict):
def keys(self): l = dict.keys(self); l.sort(); return l
def items(self): l = dict.items(self); l.sort(); return l
def values(self): return map( lambda i : i[1], self.items() )
def iteritems(self) : return iter(self.items())
def itervalues(self) : return iter(self.values())
def iterkeys(self) : return iter(self.keys())
__iter__ = iterkeys

Ну или если покороче:

class sort_dict2 :
def __init__(self) : self.table = {}
def __getattr__(self, attr):
if attr == 'values' : return map( lambda i : i[1], self.items() )
if attr in ('keys, 'items') :
l = getattr(self.table, attr)()
l.sort()
return l
if attr == '__iter__' : return iter(self.keys())
if attr.startswith('iter') : return iter(getattr(self,attr[4:])() )
return getattr(self.table, attr)

токо он не выкидывает исключение если словарь меняется во время итерирования...

AIv ★★★★★
()
Ответ на: комментарий от AIv

Ептить! Еще раз:

class sort_dict(dict):
   def keys(self): l = dict.keys(self); l.sort(); return l
   def items(self): l = dict.items(self); l.sort(); return l
   def values(self): return map( lambda i : i[1], self.items() )
   def iteritems(self) : return iter(self.items())
   def itervalues(self) : return iter(self.values())
   def iterkeys(self) : return iter(self.keys())
   __iter__ = iterkeys

class sort_dict2 :
   def __init__(self) : self.table = {}
   def __getattr__(self, attr):
      if attr == 'values' : return map( lambda i : i[1], self.items() )
      if attr in ('keys, 'items') : l = getattr(self.table, attr)(); l.sort(); return l
      if attr == '__iter__' : return iter(self.keys())
      if attr.startswith('iter') : return iter(getattr(self,attr[4:])() )
      return getattr(self.table, attr) 

AIv ★★★★★
()
Ответ на: комментарий от AIv

но ведь ключи сортировать всякий раз перед итерацией тупо!
равно как и искать в списке перебором

anonymous
()
Ответ на: комментарий от AIv

А, ну да еще методы:
   def __str__(self) :
      if not self : return '{}'
      items = self.items()
      return '{ %s : %s'%items[0] + ', %s : %s'*len(items[1:])%tuple(items[1:]) + ' }'
   __repr__ = __str__

AIv ★★★★★
()
Ответ на: комментарий от AIv

Ой, соврал: return reduce( lambda s,i : s+', %s : %s'%i, items[1:], '{%s : %s'%items[0])+'}'

Блин, ну без сортировки не обойтись.... ну можно слабать свой словарь, но делать его придется на С++ если хочешь что бы он быро работал. Если не хочешь - моно и на питоне, но на питоне результат будет много хуже чем предложенный выше - по быстродействию то же, по реализации на порядок геморнее. Просто в питоновском словаре другие критерии упорядочивания, по хэш-индексу объекта. Это имеет свои плюсы (скорость и универсальность) ну и свои минусы (некая хаотичность на взгляд пользователя). На самом деле там где нуно упорядочивание как правило моно обойтись списком кортежей.

AIv ★★★★★
()
Ответ на: комментарий от AIv

Трохи вру. Предложенный выше вар. быстрее новой питоновской реализации словаря, если словарь небольшой. Для больших словарей амсто запускаемое с нуля итерирование будет ес-но быстрее даже в чиста питоновском варианте (то есть если руками слабать на питоне словарь, но с привычными критериями упорядочивания). Но это некий экзотический случай ИМНО.....

про тупо - не тупо - завернул в класс и забыл. Че тут тупого? Ну моно хранить упорядоченный список и выдавать старую копию если словарь не был изменен... та еще развлекуха.

AIv ★★★★★
()
Ответ на: комментарий от AIv

> про тупо - не тупо - завернул в класс и забыл. Че тут тупого? Ну моно хранить упорядоченный список и выдавать старую копию если словарь не был изменен... та еще развлекуха.

унаследоваться от dict или list и переписать ручками все методы дело нехитрое. я думал может есть какой простой (но не совсем очевидный) способ.

что-то там поговаривали перед выходом 2.4 о сортированом словаре, но кажется ничего не сделали

anonymous
()
Ответ на: комментарий от AIv

наверное проще всего унаследоваться от (dict,list) и переписать добавление/удаление элементов, так чтобы оно дублировалось в оба класса, __getitem__ взять из dict а __iterate__ из list.

вот чем плох питон -- вместо того чтобы делать дело начинаешь искать красивое решение простых вопросов, вместо того чтобы сделать быстро и по-тупому ;))

кстати, (lambda x: x[1]) == itertools.itemgetter(1)

anonymous
()

"Учиться, учиться и еще раз учиться!", копирайт не помню чей,может Ленина.

Если тебе нужна сортировка - тебе нужен _не_ хеш. По определению. Тебе могут подойти некоторые варианты деревьев, или простой сортированый список c быстрым доступом (import bisect).

DonkeyHot ★★★★★
()
Ответ на: комментарий от DonkeyHot

определено:-)

Хэш. Ключем словаря может быть лишь тот объект, для которого определена функция hash. hash возвращает хэш-значени объекта используемое для сравнения ключей.

Есть модуль bisect, реализующий метод половинного деления для списков.

Вообще странно что нету в питоне rb-tree... то есть наверное оно есть, но я про него не знаю:-)

Можно кстати попытаься мсоздать свой объект для строки и возвращать хэши так что бы строки были упорядочены... возможно это самое изящное решение:-)

AIv ★★★★★
()
Ответ на: определено:-) от AIv

определено:-)

>Можно кстати попытаься мсоздать свой объект для строки и возвращать хэши так что бы строки были упорядочены... возможно это самое изящное решение

Ступил, ничего это не дает ес-но.......

AIv ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.