Вопрос:

Python сортирует несколько списков по дате и выводит список имен

python list sorting

659 просмотра

4 ответа

63 Репутация автора

Работая в Python 3.5.2, у меня есть четыре списка дат, каждый в порядке возрастания, где списки не имеют одинаковую длину. Каждый список дат генерируется путем поиска в более длинном списке дат. Пример значения даты и тип данных показаны ниже:

In: print (date, type(date))
Out: 725722.0 <class 'numpy.float64'>

Я строю каждый список дат, используя соответствующий цикл. Чтобы увидеть значения, я конвертирую в строки и распечатываю каждый список. Таким образом, я мог бы отсортировать данные по типу numpy float64 или преобразовать в строку. Соответствующие значения фактических данных в каждом списке (на основе определенных настроек фильтра) показаны ниже:

a = [12-17-1987, 11-22-1989, 03-05-1990, 11-12-1990]
b = [12-16-1987, 03-02-1990, 11-12-1990]
c = [10-09-1986, 12-16-1987, 03-05-1990, 11-12-1990]
d = [10-16-1985, 08-20-1986, 10-15-1986, 12-16-1987, 03-02-1990]

Мне нужно отсортировать даты из всех четырех списков в порядке возрастания по мм-дд-гггг, распечатать каждую дату, а рядом с каждой датой вывести имя соответствующего списка, как показано в примере ниже:

# Desired Printout
10-16-1985  d
08-20-1986  d
10-09-1986  c
10-15-1986  d
12-16-1987  b
12-16-1987  c
12-16-1987  d
12-17-1987  a
11-22-1989  a
03-02-1990  b
03-02-1990  d
03-05-1990  a
03-05-1990  c
11-12-1990  a
11-12-1990  b
11-12-1990  c

Это даст мне визуальное подтверждение последовательности событий в четырех разных наборах данных. Я попытался бы создать словарь и отсортировать по дате для печати на экран или диск, но я заметил похожие ответы, используя функции карты или лямбды, которые могут обеспечить более элегантное решение. Если я храню эту информацию на диске, какова лучшая структура данных и решение?

Автор: SystemTheory Источник Размещён: 22.08.2016 09:27

Ответы (4)


-2 плюса

938 Репутация автора

Тебе, честно говоря, не нужно ничего такого фантастического. Просто сделайте минимум на первый пункт в каждом списке. Затем проверьте, находится ли значение min в каком-либо из списков, и затем выполните list.pop () и распечатайте. Это простой способ сделать это эффективно и имеет смысл. Я мог бы предоставить вам код, но это должно быть достаточно ясно.

Автор: bravosierra99 Размещён: 22.08.2016 09:33

-1 плюса

1753 Репутация автора

#  Create the list of all dates, combining the four lists you have. Keep
#  the information about which list value comes from
all_dates = [(x, 'a') for x in a] + [(x, 'b') for x in b] + [(x, 'c') for x in c] + [(x, 'd') for x in d]

#  Sort with key a simple date parser. The way it works is:
#     1. It takes a date 11-12-2012 and splits it by '-' so that we get ['11', '12', '2012']
#     2. Reverses the list ([::-1]) so that the year is the most significant (['2012', '12', '11'])
#     3. Applies int to each so that they are compared as numbers ([2012, 12, 11]). Note that Python can automatically compare things like that
all_dates.sort(key = lambda x: list(map(int, x[0].split('-')[::-1])))

#  Print the result
for date in all_dates:
    print ' '.join(date)
Автор: Dmitry Torba Размещён: 22.08.2016 09:40

0 плюса

2754 Репутация автора

Предполагая, что все ваши даты отформатированы как mm-dd-yyyy(в отличие от вашего примера), это должно помочь:

import itertools

lists = dict(a=['7-1-1987', '1-1-1990'],
             b=['7-2-1987', '1-5-1990'],
             c=['7-1-1987', '1-3-1990'],
             d=['1-10-1985', '7-10-1986'])

for d, v in sorted(itertools.chain(*([(e, n) for e in v] for n, v in lists.items()))):
    print d, v

Если даты не отформатированы должным образом, вам потребуется добавить в функцию пользовательский ключ сортировки, sortedчтобы разобрать дату в правильно сопоставимые объекты.

Автор: sirfz Размещён: 22.08.2016 09:57

3 плюса

5712 Репутация автора

Решение

У меня есть пара комментариев к этому:

  1. «Бест» неоднозначно. Это может означать минимизацию алгоритмической сложности, минимизацию времени выполнения, минимизацию использования памяти, простоту реализации или чтения, наименьшее количество кода и т. Д.

  2. Если у вас нет тысяч записей, возможно, не стоит оптимизировать структуру данных или алгоритм. Общепринятая лучшая практика сообщества заключается в профилировании и оптимизации того, что медленно в вашей программе.

Простая реализация может быть не чем иным, как соединением списков и сортировкой их со sortedвстроенным. Например, вот несколько вариантов, которые вы могли бы рассмотреть для сортировки:

import datetime

a = ['7-1-1987', '1-1-1990']
b = ['7-2-1987', '1-5-1990']
c = ['7-1-1987', '1-3-1990']
d = ['1-10-1985', '7-10-1986']

# hold on to list name
a = [(i, 'a') for i in a]  # [(date, list_name), ...]
b = [(i, 'b') for i in b]
c = [(i, 'c') for i in c]
d = [(i, 'd') for i in d]

dates = a + b + c + d  # combine into one flat list
for i in dates: print(i)

Выход

('7-1-1987', 'a')
('1-1-1990', 'a')
('7-2-1987', 'b')
('1-5-1990', 'b')
('7-1-1987', 'c')
('1-3-1990', 'c')
('1-10-1985', 'd')
('7-10-1986', 'd')

Подход 1 - Разобрать каждую строку даты в объекте datetime, отсортировать их по месту и вывести список объектов datetime.

dates_1 = [(datetime.datetime.strptime(d, '%m-%d-%Y').date(), l) for d, l in dates]
dates_1.sort()
for i in dates_1: print(i)

Выход

(datetime.date(1985, 1, 10), 'd')
(datetime.date(1986, 7, 10), 'd')
(datetime.date(1987, 7, 1), 'a')
(datetime.date(1987, 7, 1), 'c')
(datetime.date(1987, 7, 2), 'b')
(datetime.date(1990, 1, 1), 'a')
(datetime.date(1990, 1, 3), 'c')
(datetime.date(1990, 1, 5), 'b')

Подход 2. Сортировка дат с использованием лямбда-функции, которая анализирует их на лету, и выводит (новый) список строк.

dates_2 = sorted(dates, key=lambda d: (datetime.datetime.strptime(d[0], '%m-%d-%Y').date(), d[1]))
for i in dates_2: print(i)

Выход

('1-10-1985', 'd')
('7-10-1986', 'd')
('7-1-1987', 'a')
('7-1-1987', 'c')
('7-2-1987', 'b')
('1-1-1990', 'a')
('1-3-1990', 'c')
('1-5-1990', 'b')

Подход 3 - Используйте heapq.merge для более эффективной сортировки. Благодарим @friendlydog за предложение.

import datetime
import heapq

a = ['7-1-1987', '1-1-1990']
b = ['7-2-1987', '1-5-1990']
c = ['7-1-1987', '1-3-1990']
d = ['1-10-1985', '7-10-1986']

def strs_to_dates(date_strs, list_name):
    """
    Convert a list of date strings to a generator of (date, str) tuples.
    """
    return ((datetime.datetime.strptime(date, '%m-%d-%Y').date(), list_name) for date in date_strs)

a = strs_to_dates(a, 'a')
b = strs_to_dates(b, 'b')
c = strs_to_dates(c, 'c')
d = strs_to_dates(d, 'd')

dates_3 = heapq.merge(a, b, c, d)
for i in dates_3: print(i)

Выход

(datetime.date(1985, 1, 10), 'd')
(datetime.date(1986, 7, 10), 'd')
(datetime.date(1987, 7, 1), 'a')
(datetime.date(1987, 7, 1), 'c')
(datetime.date(1987, 7, 2), 'b')
(datetime.date(1990, 1, 1), 'a')
(datetime.date(1990, 1, 3), 'c')
(datetime.date(1990, 1, 5), 'b')

Примечания:

  1. Я предположил, что формат ваших входных строк «день-месяц-год».
  2. Я предположил, что когда одна и та же дата находится в нескольких списках, вы захотите вторично отсортировать их по алфавиту по имени списка.
  3. Я оставил форматирование выходного списка в качестве упражнения для читателя.
  4. Оба примера работают под Python 2/3.

В этом примере keyаргумент является лямбда-выражением. Без этого он бы сортировал строки по алфавиту. Это позволяет нам переопределить это и отсортировать по году> месяцу> дню.

Более сложная реализация может использовать преимущество гарантии того, что списки предварительно отсортированы. В Википедии есть список алгоритмов слияния для рассмотрения.

Автор: Taylor Edmiston Размещён: 22.08.2016 10:09
Вопросы из категории :
32x32