обновлен список словарей - PullRequest
1 голос
/ 22 января 2020

У меня есть список словарей.

my_list = [
    {"id": "UU7t", "updated_at": "2020-01-06_16-40-00", "summary": "Renewed"},
    {"id": "yT8h", "updated_at": "2020-01-07_18-24-22", "summary": "Renewed"},
    {"id": "i8Po", "updated_at": "2020-01-08_13-16-36", "summary": "Renewed"},
    {"id": "yT8h", "updated_at": "2020-01-13_18-24-05", "summary": "Deleted"},
    {"id": "7uYg", "updated_at": "2020-01-18_23-37-19", "summary": "Transferred"},
]

Я хочу получить список с удаленным дубликатом словаря, где идентификатор такой же, но «updated_at» последний.

Итак, мой последний список будет:

my_list = [
    {"id": "UU7t", "updated_at": "2020-01-06_16-40-00", "summary": "Renewed"},
    {"id": "i8Po", "updated_at": "2020-01-08_13-16-36", "summary": "Renewed"},
    {"id": "yT8h", "updated_at": "2020-01-13_18-24-05", "summary": "Deleted"},
    {"id": "7uYg", "updated_at": "2020-01-18_23-37-19", "summary": "Transferred"},
]

Каким будет эффективный метод?

Ответы [ 4 ]

2 голосов
/ 22 января 2020

Вы можете использовать dict для накопления элементов.

Словарь может хранить id в качестве ключа и элемент списка в качестве значения. Вставляйте элемент в словарь только в том случае, если элемент с таким же ключом не существует; если он сравнивает значение updated_at и обновляет словарь, если необходимо.

def generate_new_list(my_list):
    counts = {}
    for d in my_list:
        item_id = d['id']
        if item_id in counts:
            if d['updated_at'] > counts[item_id]['updated_at']:
                counts[item_id] = d
        else:
            counts[item_id] = d

    return list(counts.values())

Еще несколько замечаний:

  • , если вы хотите сохранить исходный порядок, либо убедитесь, что вы используете Python 3.7 (что гарантирует, что дикты упорядочены в порядке вставки) или используете OrderedDict При стандартном dict вам сначала нужно вытолкнуть запись, так как замена 1013 * не изменяет порядок dict (поэтому каждый элемент будет выводиться в том порядке, в котором его идентификатор был впервые увиден), в то время как orderdictict имеет специальную поддержку для этот вариант использования (move_to_end).
  • Вы также можете удалить особые случаи, используя dict.get и «шаблон нулевого объекта»:

    MISSING = {'updated_at': '0'} # pseudo-entry smaller than all possible
    def generate_new_list(my_list):
        counts = {}
        for d in my_list:
            if d['updated_at'] > counts.get(d['id'], MISSING):
                counts[d['id']] = d
    
        return list(counts.values())
    
  • не Альтернативой dict (хотя тот, который очень не сохраняет порядок) является сортировка по (id, updated_by), группировка по id, а затем сохранение только последней записи. Я не думаю, что stdlib обеспечивает последнюю из готовых операций (хотя islice не принимает отрицательные индексы), поэтому вам придется либо делать это вручную, либо заново преобразовывать вложенные записи в список.
0 голосов
/ 23 января 2020

Использование pandas

import pandas as pd

df = pd.DataFrame(my_list)
df = df.sort_values(by="updated_at").drop_duplicates(subset=["id"], keep="last")

my_list = df.to_dict(orient="records")

Вывод:

[{'id': 'UU7t', 'summary': 'Renewed', 'updated_at': '2020-01-06_16-40-00'},
 {'id': 'i8Po', 'summary': 'Renewed', 'updated_at': '2020-01-08_13-16-36'},
 {'id': 'yT8h', 'summary': 'Deleted', 'updated_at': '2020-01-13_18-24-05'},
 {'id': '7uYg', 'summary': 'Transferred', 'updated_at': '2020-01-18_23-37-19'}]
0 голосов
/ 23 января 2020

Два решения, одно с использованием dict, а другое путем сортировки и группировки:

from itertools import groupby

my_list = [
    {"id": "UU7t", "updated_at": "2020-01-06_16-40-00", "summary": "Renewed"},
    {"id": "yT8h", "updated_at": "2020-01-07_18-24-22", "summary": "Renewed"},
    {"id": "i8Po", "updated_at": "2020-01-08_13-16-36", "summary": "Renewed"},
    {"id": "yT8h", "updated_at": "2020-01-13_18-24-05", "summary": "Deleted"},
    {"id": "7uYg", "updated_at": "2020-01-18_23-37-19", "summary": "Transferred"},
]


def newest_id(seq):
    """Keep id with most recent updated_at

    Return a list of kept items.
    """
    td = {}
    for e in seq:
        key = e['id']
        if key not in td or td[key]['updated_at'] < e['updated_at']:
            td[key] = e
    return list(td.values())


def newest_id2(seq):
    """Keep id with most recent updated_at

    Return a sorted list of kept items.
    """
    tl = sorted(seq, key=lambda e: (e['id'], e['updated_at']), reverse=True)
    return [next(g) for _, g in groupby(tl, key=lambda e: e['id'])]


res1 = newest_id(my_list)
res2 = newest_id2(my_list)

# Check result

res1.sort(key=lambda e: e['id'], reverse=True)
print(res1 == res2)

0 голосов
/ 22 января 2020

Один из способов сделать это - изменить структуру dict.

my_list = [
    {"id": "UU7t", "updated_at": "2020-01-06_16-40-00", "summary": "Renewed"},
    {"id": "yT8h", "updated_at": "2020-01-07_18-24-22", "summary": "Renewed"},
    {"id": "i8Po", "updated_at": "2020-01-08_13-16-36", "summary": "Renewed"},
    {"id": "yT8h", "updated_at": "2020-01-13_18-24-05", "summary": "Deleted"},
    {"id": "7uYg", "updated_at": "2020-01-18_23-37-19", "summary": "Transferred"},
]

def getNewUpdated(myList):
    newList = {}
    for element in myList:
        if (element["id"] not in newList):
            newList[element["id"]] = element
        elif (element["updated_at"] >= newList[element["id"]]["updated_at"]):
            newList[element["id"]] = element
    return newList

print(getNewUpdated(my_list))

Здесь мы реструктурируем dict, так что «id» - это ключ, а все элементы - «значения», и затем выполните итерации по предоставленному вами списку, чтобы проверить, существует ли уже «id» в newList, если он существует, затем просто обновите ту же запись (при условии, что время обновления новое) или добавьте новую запись.

Вывод это что-то вроде этого:

{
 'i8Po': {'summary': 'Renewed', 'id': 'i8Po', 'updated_at': '2020-01-08_13-16-36'},
 'yT8h': {'summary': 'Deleted', 'id': 'yT8h', 'updated_at': '2020-01-13_18-24-05'},
 '7uYg': {'summary': 'Transferred', 'id': '7uYg', 'updated_at': '2020-01-18_23-37-19'},
 'UU7t': {'summary': 'Renewed', 'id': 'UU7t', 'updated_at': '2020-01-06_16-40-00'}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...