【问题标题】:Python: get most recent date per companyPython:获取每家公司的最新日期
【发布时间】:2017-10-06 13:39:29
【问题描述】:

我有一个元组列表,其中包含日期和公司名称。一家公司可以列出多个日期的信息:

 [(Company A, datetime.date(1980,1,30)),
  (Company A, datetime.date(1990,1,30)),
  (Company B, datetime.date(1990,1,30)),
  (Company B, datetime.date(2000,1,30))]

我想做的是有一个列表,其中只包含每家公司可用的最近日期,即结果:

 [(Company A, datetime.date(1990,1,30)),
  (Company B, datetime.date(2000,1,30))]

有什么想法吗?

【问题讨论】:

  • 到目前为止您尝试过什么,我们需要使用代码。 How to create a Minimal, Complete, and Verifiable example
  • 我认为这是与列表理解有关的东西,但我有点迷茫。也许从 [(i,j) for i,j in company if max(j) for set (i)] 开始]
  • 我们不想为您编写代码。这其中的乐趣在哪里?但我建议你看看reduce

标签: python list list-comprehension


【解决方案1】:

如何使用来自 itertools 的 groupby,然后取最大值:

import datetime
x = [('Company A', datetime.date(1980,1,30)),
  ('Company A', datetime.date(1990,1,30)),
  ('Company B', datetime.date(1990,1,30)),
  ('Company B', datetime.date(2000,1,30))]

import itertools
out = []
for k,g in itertools.groupby(sorted(x, key = lambda y: y[0]), lambda y: y[0]):
    out.append(max(g, key = lambda y:y[1]))

out
[('Company A', datetime.date(1990, 1, 30)),
 ('Company B', datetime.date(2000, 1, 30))]

【讨论】:

  • groupby 的问题在于它希望同一组的成员是连续的。将list(groupby('abcabcabc')) 的结果与list(groupby('aaabbbccc')) 的结果进行比较。如果不能保证列表的元素按公司分组,您提出的方案将失败。在您的具体示例中,如果您交换 x 中的中间两个元素,您将在 out 中得到 4 个元素。
  • 排序会解决语义问题,但它确实将解决方案的算法复杂度从 O(n) 增加到 O(n log n)我>。因此,如果您的数据集足够大,并且您在程序中经常这样做,那么它可能会比寻找线性解决方案的成本高得多。
【解决方案2】:

你也可以使用字典...

data = [('Company A', '1980,1,30'),
  ('Company A', '1990,1,30'),
  ('Company B', '1990,1,30'),
  ('Company B', '2000,1,30')]

datadict = { a:b for a,b in data }

for a, b in data:
    datadict[a] = max(b, datadict[a])

print(datadict)

【讨论】:

  • 通过使用dict 作为变量,您正在隐藏内置的dict:隐藏内置不是一个好主意。
  • 如果您真的需要成对列表中的结果,那么只需在 Python 2 中使用 datadict.items(),在 Python 3 中使用 list(datadict.items())
【解决方案3】:

这是一个使用reduce()的例子:

import datetime

company_dates = [
  ('Company A', datetime.date(1980,1,30)),
  ('Company A', datetime.date(1990,1,30)),
  ('Company B', datetime.date(1990,1,30)),
  ('Company B', datetime.date(2000,1,30)),
]

def reducer(acc, company_date):
  try:
    acc[company_date[0]] = max(acc[company_date[0]], company_date[1])
  except KeyError:
    acc[company_date[0]] = company_date[1]

  return acc

sorted = reduce(reducer, company_dates, {})

print sorted.items()

这是使用不同功能的另一种替代解决方案:

import datetime
import operator

company_dates = [
  ('Company A', datetime.date(1980,1,30)),
  ('Company A', datetime.date(1990,1,30)),
  ('Company B', datetime.date(1990,1,30)),
  ('Company B', datetime.date(2000,1,30)),
]

sorted = sorted(company_dates, key=operator.itemgetter(0, 1), reverse=True)
unique = set([company_date[0] for company_date in sorted])
top = [next(c for c in sorted if c[0] == company) for company in unique]

print top

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-12
    • 1970-01-01
    相关资源
    最近更新 更多