根据现有的词典列表创建过滤的词典列表

时间:2018-04-13 18:12:41

标签: python dictionary

我有一个从csv DictReader读入的词典列表,它代表了一个csv文件的行:

    rows = [{"id":"123","date":"1/1/18","foo":"bar"},
            {"id":"123","date":"2/2/18", "foo":"baz"}]

我想创建一个新的字典,其中只存储唯一的ID。但我想只保留最近日期的行条目。根据上面的例子,它将保持行的日期为2/2/18。

我正在考虑做这样的事情,但是在将else语句中的伪代码转换为实际的python时遇到了麻烦。

我可以弄清楚检查两个日期更近期的部分,但最麻烦的是弄清楚我如何检查包含相同id的字典的新列表,然后从该行检索日期。

注意:遗憾的是,由于我们平台上的资源限制,我无法在此项目中使用pandas。

new_data = []
for row in rows:
    if row['id'] not in new_data:
        new_data.append(row)
    else:
        check the element in new_data with the same id as row['id']
        if that element's date value is less recent: 
            replace it with the current row
        else :
            continue to next row in rows

4 个答案:

答案 0 :(得分:1)

import datetime

rows = [{"id":"123","date":"1/1/18","foo":"bar"},
            {"id":"123","date":"2/2/18", "foo":"baz"}]

def parse_date(d):
    return datetime.datetime.strptime(d, "%d/%m/%y").date()

tmp_dict = {}
for row in rows:
    if row['id'] not in tmp_dict.keys():
        tmp_dict['id'] = row
    else:
        if parse_date(row['date']) > parse_date(tmp_dict[row['id']]):
            tmp_dict['id'] = row


print tmp_dict.values()

输出

[{'date': '2/2/18', 'foo': 'baz', 'id': '123'}]

注意:您可以将两个if合并到if row['id'] not in tmp_dict.keys() || parse_date(row['date']) > parse_date(tmp_dict[row['id']]),以获得更清晰,更短的代码

答案 1 :(得分:1)

您需要一个函数将日期(作为字符串)转换为日期(作为日期)。

import datetime

def to_date(date_str):
  d1, m1, y1 = [int(s) for s in date_str.split('/')]
  return datetime.date(y1, m1, d1)

我假设你的日期格式是d / m / yy。考虑使用datetime.strptime来解析您的日期,如Alex Hall的回答所示。

然后,我们的想法是遍历你的行并将它们存储在一个新结构中(这里是一个dict,其键是ID)。如果密钥已存在,请将其日期与当前行进行比较,然后选择正确的行。遵循您的伪代码,这会导致:

rows = [{"id":"123","date":"1/1/18","foo":"bar"},
        {"id":"123","date":"2/2/18", "foo":"baz"}]

new_data = dict()
for row in rows:
    existing = new_data.get(row['id'], None)
      if existing is None or to_date(existing['date']) < to_date(row['date']):
          new_data[row['id']] = row

如果您希望new_data变量成为列表,请使用new_data = list(new_data.values())

答案 2 :(得分:0)

首先,使用正确的日期对象,而不是字符串。以下是解析它们的方法:

field

(检查格式是否正确)

然后是实际任务:

from datetime import datetime, date

rows = [{"id": "123", "date": "1/1/18", "foo": "bar"},
        {"id": "123", "date": "2/2/18", "foo": "baz"}]

for row in rows:
    row['date'] = datetime.strptime(row['date'], '%d/%m/%y').date()

可替换地:

以下是一些在这里运行良好的通用实用程序函数,我在很多地方都使用它:

new_data = {}
for row in rows:
    new_data[row['id']] = max(new_data.get(row['id'], date.min),
                              row['date'])

print(new_data.values())

然后解决方案可以写成:

from collections import defaultdict

def group_by_key_func(iterable, key_func):
    """
    Create a dictionary from an iterable such that the keys are the result of evaluating a key function on elements
    of the iterable and the values are lists of elements all of which correspond to the key.
    """
    result = defaultdict(list)
    for item in iterable:
        result[key_func(item)].append(item)
    return result

def group_by_key(iterable, key):
    return group_by_key_func(iterable, lambda x: x[key])

这比第一个解决方案效率低,因为它会沿着被丢弃的方式创建列表,但我在很多地方都使用了一般原则,我首先想到了它,所以在这里。

答案 3 :(得分:0)

如果你像我一样喜欢上课,那么你可以自己上课来做这个:

from datetime import date
rows = [
    {"id":"123","date":"1/1/18","foo":"bar"},
    {"id":"123","date":"2/2/18", "foo":"baz"},
    {"id":"456","date":"3/3/18","foo":"bar"},
    {"id":"456","date":"1/1/18","foo":"bar"}
]

class unique(dict):
    def __setitem__(self, key, value):
        #Add key if missing or replace key if date is newer
        if key not in self or self[key]["date"] < value["date"]:
            dict.__setitem__(self, key, value)

data = unique()                   #Initialize new class based on dict
for row in rows:
    d, m, y = map(int, row["date"].split('/')) #Split date into parts
    row["date"] = date(y, m, d)   #Replace date value
    data[row["id"]] = row         #Set new data. Will overwrite same ids with more recent

print data.values()

输出:

[
    {'date': datetime.date(18, 2, 2), 'foo': 'baz', 'id': '123'},
    {'date': datetime.date(18, 3, 3), 'foo': 'bar', 'id': '456'}
]

请注意,data是一个dict,它基本上会覆盖使用ID作为键的__setitem__方法。日期为date个对象,因此可以轻松比较它们。