Python: преобразование списка кортежей в словарь с некоторыми условиями - PullRequest
0 голосов
/ 19 мая 2018

Я создал такой список:

Book = [(24, '2008-10-30', 'Start'), (24, '2008-12-20', 'End','sold'), 
 (25, '2009-01-01', 'Start'), (25, '2009-11-14', 'End', 'returned'),
 (26, '2010-04-03', 'Start'), (26, '2010-10-11', 'End', 'sold'),...]

Я хочу преобразовать его в словарь, подобный этому:

bookDict = { 24: {'Start': '2008-10-30', 'End': '2008-12-20','reason':'sold'},
  25: {'Start': '2009-01-01', 'End': '2009-11-14','reason':'returned'},
  26: {'Start': '2010-04-03', 'End': '2010-10-11','reason':'sold'},...}

Для каждого ключа в словаре, который является первым значениемиз кортежей в списке книг (это код), я хочу иметь два кортежа в качестве значений каждого ключа.Один из них связан с точкой «начала», а другой связан с точкой «Конца» этого конкретного кода.

У меня есть еще один вопрос.Для некоторых кодов существует несколько «конечных» точек с разными датами.Я хочу сохранить только конечную точку с более поздней датой.что-то вроде этого:

Book = [(24, '2008-10-30', 'Start'), (24, '2008-12-20', 'End', 'sold'), 
 (24, '2009-02-04', 'End', 'sold'), (24, '2009-11-25', 'End', 'sold')]

Для приведенного выше примера словарь должен сохранить это:

bookDict = { 24: {'Start': '2008-10-30', 'End': '2009-11-25','reason':'sold'},

Может кто-нибудь помочь мне, пожалуйста?

Ответы [ 4 ]

0 голосов
/ 19 мая 2018

Это отвечает только на первую часть вопроса ОП, хотя она может быть адаптирована для второй.

Вы можете использовать collections.defaultdict для решения O (n):

book = [(24, '2008-10-30', 'Start'), (24, '2008-12-20', 'End','sold'), 
        (25, '2009-01-01', 'Start'), (25, '2009-11-14', 'End', 'returned'),
        (26, '2010-04-03', 'Start'), (26, '2010-10-11', 'End', 'sold')]

from collections import defaultdict

d = defaultdict(dict)

for key, date, *data in book:
    d[key][data[0]] = date
    if len(data) == 2:
        d[key]['reason'] = data[1]

Кроме того, вы можете поймать IndexError вместо проверки длины кортежа:

for key, date, *data in book:
    d[key][data[0]] = date
    try:
        d[key]['reason'] = data[1]
    except IndexError:
        continue
0 голосов
/ 19 мая 2018

Вот решение, которое удовлетворяет обоим критериям.

Каждый раз, когда он инкапсулирует новый идентификатор книги, он создает для него dict и заполняет его, когда встречает данные в вашем list.

Что касается нескольких записей Конец , формат даты позволяет использовать сравнение строк для получения самой последней даты.

books = [(24, '2008-10-30', 'Start'), (24, '2008-12-20', 'End','sold'),
 (25, '2009-01-01', 'Start'), (25, '2009-11-14', 'End', 'returned'),
 (26, '2010-04-03', 'Start'), (26, '2010-10-11', 'End', 'sold'),
 (26, '2011-10-11', 'End', 'returned')] # The latest 'End' entry should be picked

bookDict = {}

for info in books:
    id_ = info[0]
    type_ = info[2]

    book = bookDict.setdefault(id_, {})

    if type_ == 'Start':
        book[type_] = info[1]

    elif type_ == 'End' and info[1] > book.get(type_, ''):
        book[type_] = info[1]
        book['reason'] = info[3]

Вывод:

bookDict
# {24: {'Start': '2008-10-30', 'End': '2008-12-20', 'reason': 'sold'},
#  25: {'Start': '2009-01-01', 'End': '2009-11-14', 'reason': 'returned'},
#  26: {'Start': '2010-04-03', 'End': '2010-10-11', 'reason': 'returned'}}
0 голосов
/ 19 мая 2018

Вы можете сделать что-то вроде этого:

for t in Book:
    index, date, marker, *rest = t
    entry = d.setdefault(index, {})
    end_date = entry.get("End", "1900-01-01")
    if marker == "Start" or date > end_date:
        entry[marker] = date
        if rest:
            entry["reason"] = rest[0]
0 голосов
/ 19 мая 2018

Вы можете использовать itertools.groupby, min и max:

import itertools
def quantity_key(d):
  return list(map(int, d[1].split('-')))

Book = [(24, '2008-10-30', 'Start'), (24, '2008-12-20', 'End','sold'), (25, '2009-01-01', 'Start'), (25, '2009-11-14', 'End', 'returned'), (26, '2010-04-03', 'Start'), (26, '2010-10-11', 'End', 'sold')]
new_books = {a:list(b) for a, b in itertools.groupby(Book, key=lambda x:x[0])}
final_books = {a:{'Start':min(b, key=quantity_key)[1], 'End':max(b, key=quantity_key)[1], 'reason':max(b, key=quantity_key)[-1]} for a, b in new_books.items()}

Выход:

{24: {'Start': '2008-10-30', 'End': '2008-12-20', 'reason': 'sold'}, 25: {'Start': '2009-01-01', 'End': '2009-11-14', 'reason': 'returned'}, 26: {'Start': '2010-04-03', 'End': '2010-10-11', 'reason': 'sold'}}

С более чем двумя значениями для каждой клавиши:

Book = [(24, '2008-10-30', 'Start'), (24, '2008-12-20', 'End', 'sold'), (24, '2009-02-04', 'End', 'sold'), (24, '2009-11-25', 'End', 'sold')]
new_books = {a:list(b) for a, b in itertools.groupby(Book, key=lambda x:x[0])}
final_books = {a:{'Start':min(b, key=quantity_key)[1], 'End':max(b, key=quantity_key)[1], 'reason':max(b, key=quantity_key)[-1]} for a, b in new_books.items()}

Вывод:

{24: {'Start': '2008-10-30', 'End': '2009-11-25', 'reason': 'sold'}}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...