0

我有电子邮件和日期。我可以使用 2 个嵌套的 for 循环来选择在同一日期发送的电子邮件,但我怎样才能“聪明地”做到这一点 - 高效?

# list of tuples - (email,date)

for entry in list_emails_dates:
    current_date = entry[1]
    for next_entry in list_emails_dates:
        if current_date = next_entry[1]
        list_one_date_emails.append(next_entry)

我知道它可以用更短的代码编写,但我不知道itertools,或者也许使用map, xrange

4

2 回答 2

2

您可以通过将与日期相关的所有电子邮件收集到同一个键中来将其转换为字典。

为此,您需要使用defaultdictfrom 集合。为字典中的新键赋予默认值是一种简单的方法。

这里我们传入函数 list,这样字典中的每个新键都会得到一个列表作为默认值。

emails = defaultdict(list)
for email,email_date in list_of_tuples:
    emails[email].append(email_date)

现在,您emails['2013-14-07']将拥有该日期的电子邮件列表。

如果我们不使用defaultdict, 并像这样进行字典理解:

emails = {x[1]:x[0] for x in list_of_tuples}

每个日期都有一个条目,这将是该日期的最后一封电子邮件,因为分配给相同的键将覆盖其值。字典是通过键查找值的最有效方式。如果您想通过它在一系列值中的位置来查找一个值(假设您知道它的位置),那么列表是很好的。

如果由于某种原因你不能重构它,你可以使用这个模板方法,它会创建一个生成器:

def find_by_date(haystack, needle):
    for email, email_date in haystack:
        if email_date == needle:
            yield email

以下是您将如何使用它:

>>> email_list = [('foo@bar.com','2014-07-01'), ('zoo@foo.com', '2014-07-01'), ('a@b.com', '2014-07-03')] 
>>> all_emails = list(find_by_date(email_list, '2014-07-01'))
>>> all_emails
['foo@bar.com', 'zoo@foo.com']

或者,您可以这样做:

>>> july_first = find_by_date(email_list, '2014-07-01')
>>> next(july_first)
'foo@bar.com'
>>> next(july_first)
'zoo@foo.com'
于 2014-07-27T08:17:51.190 回答
2

我会做一个(尝试使用 itertools 很好)

itertools.groupby(list_of_tuples, lambda x: x[1])

它为您提供按日期 (x[1]) 分组的电子邮件列表。请注意,当您执行此操作时,您必须针对相同的组件 ( sorted(list_of_tuples, lambda x: x[1])) 对其进行排序。

一件好事(除了告诉读者我们做一个分组)是它的工作是惰性的,如果列表有点长,它的性能主要由n log n排序而不是n^2嵌套循环支配。

于 2014-07-27T08:49:12.073 回答