从列表列表中提取最小值和最大值

时间:2015-01-21 17:25:00

标签: python python-2.7

我有一个名为projects的项目列表,以及与每个项目相关联的名为tasks的任务列表。有些项目没有任务,有些任务尚未完成。一些项目也有多项任务。我想生成一个列表列表,显示每个项目,最早的任务开始日期和最新的任务结束日期。如果任务尚未完成,则结束日期应为None。如果项目没有任务,那么开始和结束日期应该None

我的代码会产生错误的结果,所以我想知道原因,但也看看是否有人建议采用更有效的方法。

任务格式:

[项目ID,开始日期,结束日期]

我的代码:

import datetime
tasks = [['ID1', datetime.datetime( 2015, 1, 1), datetime.datetime( 2015, 1, 2)],
       ['ID1', datetime.datetime( 2015, 10, 1), None],
       ['ID2', datetime.datetime( 2015, 1, 1), datetime.datetime( 2015, 1, 3)]]

projects = [['ID1'], ['ID2'], ['ID3']]

for key, item in enumerate(projects):
    if item[0] not in tasks:
         item.append(None)
         item.append(None)
    else:
        start_date = [x[1:-1] for x in tasks if x[0] == item[0]]
        item.append(min(start_date))
        end_date = [x[-1] for x in tasks if x[0] == item[0]]
        if end_date.count(None) <> 0: #checks to see if there is a None value
            item.append(None)
        else:
            item.append(max(end_date))


print projects

我的输出:

[['ID1', None, None], ['ID2', None, None], ['ID3', None, None]]

期望的输出:

[['ID1', datetime.datetime( 2015, 1, 1), None], ['ID2', datetime.datetime( 2015, 1, 1), datetime.datetime( 2015, 1, 3)], ['ID3', None, None]]

2 个答案:

答案 0 :(得分:3)

你的问题在

if item[0] not in tasks:

因为这会检查字符串&#39; IDx&#39;是任务列表的成员。但是,任务是一个列表列表 - 因此它不会直接包含字符串&#34;&#34;。

我的建议是将任务更改为字典 - 比如

tasks = {'ID1': [datetime.datetime( 2015, 1, 1), datetime.datetime( 2015, 1, 2)],
   'ID1': [datetime.datetime( 2015, 10, 1), None],
   'ID2': [datetime.datetime( 2015, 1, 1), datetime.datetime( 2015, 1, 3)]}

如果您没有数百万个条目,这应该一样快,但检查条目更容易,更直观。 我的想法是你可以检查'ID1' in tasks,它将返回True - 因为在字典上进行的检查是在定义dict访问的键上进行的,即ID在上面给出的一个dict的例子中。

完整的解决方案可能如下所示:

import datetime
tasks = {'ID1':[[datetime.datetime( 2015, 1, 1), datetime.datetime( 2015, 1, 2)], [datetime.datetime( 2015, 10, 1), None]],
     'ID2':[[datetime.datetime( 2015, 1, 1), datetime.datetime( 2015, 1, 3)]]
    }

projects = [['ID1'], ['ID2'], ['ID3']]

for key, item in enumerate(projects):
if item[0] not in tasks:
    item.append(None)
    item.append(None)
else:
    start_date = [x[0] for x in tasks[item[0]]]
    if start_date.count(None) != 0: #checks to see if there is a None value
        item.append(None)
    else:
        item.append(min(start_date))
    end_date = [x[1] for x in tasks[item[0]]]
    if end_date.count(None) != 0: #checks to see if there is a None value
        item.append(None)
    else:
        item.append(max(end_date))


print projects

输出结果为:

[['ID1', datetime.datetime(2015, 1, 1, 0, 0), None], ['ID2', datetime.datetime(2015, 1, 1, 0, 0), datetime.datetime(2015, 1, 3, 0, 0)], ['ID3', None, None]]

如果你想完全转到字典,即包括项目数据,这就是答案:

import datetime
tasks = {'ID1':[[datetime.datetime( 2015, 1, 1), datetime.datetime( 2015, 1, 2)], [datetime.datetime( 2015, 10, 1), None]],
         'ID2':[[datetime.datetime( 2015, 1, 1), datetime.datetime( 2015, 1, 3)]]
        }

projects = [['ID1'], ['ID2'], ['ID3']]
projects_dict = {}

for key, item in enumerate(projects):
    projects_dict[item[0]] = []
    if item[0] not in tasks:
        projects_dict[item[0]].append(None)
        projects_dict[item[0]].append(None)
    else:
        start_date = [x[0] for x in tasks[item[0]]]
        if start_date.count(None) != 0: #checks to see if there is a None value
            projects_dict[item[0]].append(None)
        else:
            projects_dict[item[0]].append(min(start_date))
        end_date = [x[1] for x in tasks[item[0]]]
        if end_date.count(None) != 0: #checks to see if there is a None value
            projects_dict[item[0]].append(None)
        else:
            projects_dict[item[0]].append(max(end_date))


print projects_dict

哦,而且dict-only方法的结果(我认为这是首选的)是:

{'ID2': [datetime.datetime(2015, 1, 1, 0, 0), datetime.datetime(2015, 1, 3, 0, 0)], 'ID3': [None, None], 'ID1': [datetime.datetime(2015, 1, 1, 0, 0), None]}

编辑:fyi - 在Python中将列表列表转换为dicts的一般方法是(以下不是最简洁的,但它是最容易理解的):

dictionary = {}
for list in list_of_lists:
    dictionary[list[0]] = list[1:]

答案 1 :(得分:0)

这里最简单的修正是替换线:

if item[0] not in tasks:

有类似的东西:

if not any((item[0] in x for x in tasks))

使用像@cleros建议的字典是一种更好的方法,如果它适用于其余的代码,特别是如果ID s更像是键而不仅仅是列表的第一个元素。

另外,我建议的方法效率低下,但这并不重要。如果效率很重要,您还可以创建一个中间列表或设置为使用

tasks进行检查
task_keys = [task[0] for task in tasks]

然后:

item[0] not in task_keys

(旁白:else以下有很多问题,所以如果这条线修好后事情不会立即发挥作用,请不要感到惊讶。)