LINUX.ORG.RU

[python] Помогите с алгоритмом

 


0

1

Копаюсь сейчас с API твиттера через библиотеку tweepy. Там через метод status.created_at можно получить дату поста в формате YYYY-MM-DD HH:MM:SS.

Как можно при получении ленты их все рассортировать в группы по датам? Т.е. чтобы выходной файл выглядел примерно так:

2010
...Февраль
......твит5
......твит4
...Март
......твит3
2009
...Декабрь
......твит2
......твит1

Что-то я себе мозг сломал. Примерно понимаю, что через несколько for надо делать, но вот как...туплю.

> Примерно понимаю, что через несколько for надо делать

как раз for нужен только один. (который перебирает все твиты поочереди)

, а вот if — нужно много [каждый if на: год, месяц, день,]

каждый if проверяет — нужно ли печатать <чтото> или это <чтото> тоже самое как и прошлое :-)

user_id_68054 ★★★★★
()
Ответ на: комментарий от user_id_68054
прошлый_твит = NONE
ЦЫКЛ твит ИЗ всех_твитов:
    ЕСЛИ твит.год != прошлый_твит.год ТО
       ПЕЧАТАТЬ твит.год
    КОНЕЦ_ЕСЛИ

    ЕСЛИ твит.месяц != прошлый_твит.месяц ТО
       ПЕЧАТАТЬ твит.месяц
    КОНЕЦ_ЕСЛИ

    ЕСЛИ твит.день != прошлый_твит.день ТО
       ПЕЧАТАТЬ твит.день
    КОНЕЦ_ЕСЛИ

    ПЕЧАТАТЬ твит.текст_сообщения

    прошлый_твит = трит
КОНЕЦ_ЦЫКЛА
user_id_68054 ★★★★★
()
Ответ на: комментарий от user_id_68054

а вот if — нужно много [каждый if на: год, месяц, день,] каждый if проверяет — нужно ли печатать <чтото> или это <чтото> тоже самое как и прошлое :-)

Хм, кстати да, скорее всего как-то так извращаться придётся:) Вот только ещё небольшая проблема - твиты он берёт кучами по 200. И мне интересно, он их каждый по отдельности обрабатывает и строчечкой записывает или сразу пачкой?

Код вот такой:

while page <= max_pages:
    tweetlist = api.user_timeline('username', page=page, count=200)
    for status in tweetlist:
        f.write(status.user.name.encode('utf-8') + ' - ' + str(status.created_at.year) + ' - ' + status.text.encode('utf-8') + "\n")
    print 'Page number ' + str(page) + ' printed...'
    time.sleep(10)
    page = page + 1

mega_venik ★★★
() автор топика

>Как можно при получении ленты их все рассортировать в группы по датам?

2010
...Февраль
......твит5
......твит4
...Март
......твит3
2009
...Декабрь
......твит2
......твит1

Осилить деревья.

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

> наверно ясно :-)

Ну да, завтра попробую, спасибо) Сейчас уже ночь - голова слабо варит:)

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

> Осилить деревья.

а ведь и правду говорит анонимус! это ж класический (школьный) случай алгоритма «обхода деревьа»!

правда... не в деревьях данные предоставляются видимо (а в списках :)) :-D

а есть в стандартной библиотеке Пайтона чтонить про деревья кстате?

user_id_68054 ★★★★★
()

Собственно, вот как можно рассортировать по годам\месяцам.

from collections import defaultdict

year_bucket = defaultdict(lambda: defaultdict(list))

# После чего

year_bucket[2010][1].append('one')
year_bucket[2010][1].append('two')
year_bucket[2010][2].append('three')
year_bucket[2011][2].append('four')

# где 'one', 'two', и т.д. - твиты

# после этого имеем
# {
#    2010: {
#            1: ['one', 'two'],
#            2: ['three',],
#    },
#    2011: {
#            2: ['four',],
#    }
# }

и так далее, все «просто работает».

При выводе достаточно отсортировать по нужному индексу (т.е. год или, там, месяц) и все.

shylent
()
hash = dict()
for page_num in xrange(max_page + 1):
    for tweet in tweets_on_page(page_num):
        year, month = tweet.year, tweet.month
        if year not in hash:
            hash[year] = {}
        if month not in hash[year]:
            hash[year][month] = []
        hash[year][month].append(tweet)

Если твиты отсортированы в порядке создания, то этот алгоритм можно оптимизировать, но в целом и так нормально.

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

Какой смысл вручную инициализировать несуществующие ключи, если есть collections.defaultdict?

Если твиты отсортированы в порядке создания, можно вместо collections.defaultdict применить комбинацию collections.defaultdict и collections.OrderedDict. Примерно так:

from collections import defaultdict, OrderedDict

class OrderedDefaultDict(defaultdict, OrderedDict):
    def __init__(self, default_factory=None):
        defaultdict.__init__(self, default_factory)
        OrderedDict.__init__(self)

(Не тестировал, - нету python 2.7 под рукой, а пакет с OrderedDict не установлен)

Тогда порядок ключей будет соответствовать порядку, в котором они в него были добавлены.

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

Стандарт для всех ненаколенных приложений на Python - работать на любой версии интерпретатора начиная с 2.3. Модуль collections появился только в Python 2.4

tarc
()

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

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

Пардон, какой стандарт? Чей?

Если нужно деплоить на действительно консервативные системы (например RHEL, там, кажется, сейчас самый старый python по умолчанию стоит), есть не велосипедостроительные решения. Три основных пути:

  • Множество модулей, добавленных в стандартную библиотеку, доступны как standalone-пэкэджи на PyPi. Можно при инсталляции (автоматически) доставлять недостающие модули\пэкэджи.
  • Иногда есть смысл тащить с собой compat-модули прямо в составе приложения, то есть отдельные, бэкпортированные из свежих версий, фрагменты стандартной библиотеки (так поступают некоторые фреймворки). help(ImportError).
  • Наконец, программа-максимум, - вполне можно изолированно ставить полное окружение, включая актуальные бинарники python. Я и такое видел. Вероятно, это тоже бывает оправдано.
shylent
()
Ответ на: комментарий от tarc

> Стандарт для всех ненаколенных приложений на Python - работать на любой версии интерпретатора начиная с 2.3.

думаю что НЕТ. для _новых_ python-проложений — хватит и Python-2.5
(или же даже [О БОЖЕ!] Python-3.1 :-) :-) )

(если взять более мелкую минимальную версию — то СИЛЬНО потеряется эффективность разработки. хотя и даже Python-2.5 её снизает достаточно)

всякие там python-приложения которые работает на Python-2.3 — просто в силу _исторических_ соображений работают на Python-2.3 [было решено не ломать совместимость], а не из соображений «давайте сделаем чтобы шло везде!»


ориентироватсья нада НА:

1. на _текущие_ стабильные версии интерпретаторов и библиотек
(а «завтра» они будут уже устаревшими, хотя разрабатываемый проект возможно будет зарелизин даже «послезавтра» :))

2. на текущее _состояние_ стабильных версий _дистрибутивов_
(например в текущем стабильном Дебиане («Lenny» 4.X) — Python версии 2.5 . но скоро «Lenny» уже устарет и на смену ему придёт Debian с Python-версией повидимому 2.6 (не 2.7))

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

> При выводе достаточно отсортировать по нужному индексу (т.е. год или, там, месяц) и все.

или тогда уж — при выходе (запись в файл) достаточно просто сделать YAML-dump :-)

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

>Стандарт для всех ненаколенных приложений на Python - работать на любой версии интерпретатора начиная с 2.3

Для наколенных - скорее таки с 2.4. Он в rhel 5, а наколенные на более старые вещи не поставят.

В остальных популярных дистрибутивах он свежее, например в дебиане ленни стоит 2.5, и есть бэкпортированные модули (например python-multiprocessing)

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

Простые конструкции - это хорошо (нет, правда, если хочется понять, как работает алгоритм, - самое то).

Я бы очень порекомендовал ознакомиться со стандартными модулями itertools и collections.

Поможет избежать излишних попыток изобрести квадратное колесо (особенно itertools!), а также нередко дает прирост производительности.

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

>Поможет избежать излишних попыток изобрести квадратное колесо (особенно itertools!), а также нередко дает прирост производительности.

Зато попытки изобрести колесо вместо itertools дают вполне приятный опыт, благо там достаточно хитрые вещи иногда делаются.

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

Все так.

Плюс к тому, на странице документации есть «ответы», - листинги алгоритмов, присутствующих в itertools, «открытым текстом». itertools в текущей версии реализованы непосредственно с помощью C API.

То есть можно написать самому, а потом посмотреть, насколько это «похоже на правду».

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

> Я бы очень порекомендовал ознакомиться со стандартными модулями itertools и collections.

Спасибо, обязательно ознакомлюсь:)

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

А если азписи в случайном порядке то не получится ли список вроде

2010
...Февраль
......твит5
......твит4
...Март
......твит3
2009
...Декабрь
......твит2
......твит1
2010
...Апрель
......твит6
......твит8

Т.е надо сначала список отсортировать по дате ;)

Лучше в хеш складывать по дате чтобы получалась структура типа $hash{year}{month}{day}=[твтит1,твит2..] - потом печатать.

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

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

Питона не знаю, но надеюсь что работа с массивами там во всех версиях поддерживается одинаково.

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

> А если азписи в случайном порядке то не получится ли список вроде

да да.. всё подразумевалось что они не в случайном :-) [ видимо про это и пытался сказать товарищь: http://j.mp/cdzYZ7 ]

а ещё там бага в том что если:
* 2005-ноябрь: блфблфблф
* 2006-ноябрь: другое-блаблабла


то получиться тоже несуразиться (месяц второй раз не напечатается :-))

такчто при проверке прошлого_месяцца — надо заодно проверять и прошлый год...

...а при проверке прошлого_дня — нада проверять заодного и прошлый_месяц и прошлый_год :-)

(вобщем явно както нерационально придумано мной :))

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