Python中的"reduce"函数不能用于"namedtuple"吗?

5

我有一个采用以下格式的日志文件:

datetimestring \t username \t transactionName \r\n

我正在尝试对这个数据集进行一些统计分析。我有以下代码:

import time
import collections
file = open('Log.txt', 'r')

TransactionData = collections.namedtuple('TransactionData', ['transactionDate', 'user', 'transactionName'])
transactions = list()

for line in file:
    fields = line.split('\t')

    transactionDate = time.strptime(fields[0], '%Y-%m-%d %H:%M:%S')
    user = fields[1]
    transactionName = fields[2]

    transdata = TransactionData(transactionDate, user, transactionName)
    transactions.append(transdata)

file.close()

minDate = reduce(lambda x,y: min(x.transactionDate, y.transactionDate), transactions)
print minDate

我不想为这么简单的数据集定义一个类,所以我使用了命名元组。但是当我尝试运行时,出现了以下错误:

Traceback (most recent call last):
  File "inquiriesStat.py", line 20, in <module>
    minDate = reduce(lambda x,y: min(x.transactionDate, y.transactionDate), transactions)
  File "inquiriesStat.py", line 20, in <lambda>
    minDate = reduce(lambda x,y: min(x.transactionDate, y.transactionDate), transactions)
AttributeError: 'time.struct_time' object has no attribute 'transactionDate'

看起来Lambda函数直接操作'transactionDate'属性而不是传入整个元组。如果我将Lambda改为:

lambda x,y: min(x, y)

它按照我所期望的方式运作。有什么想法为什么会这样呢?


我相信在没有“reduce”的世界中... - JBernardo
1个回答

6

只需使用以下代码:

minDate = min(t.transactionDate for t in transactions)

以下是您的代码无法正常工作的原因解释。
假设 transactions = [t1, t2, t3],其中t1...t3是三个命名元组。
根据reduce的定义,您的代码:
reduce(lambda x,y: min(x.transactionDate, y.transactionDate), transactions)

等同于

min(min(t1.transactionDate, t2.transactionDate).transactionDate, t3.transactionDate)

显然,内部的min()返回的是time.struct_time而不是一个命名元组,因此当reduce试图将.transactionDate应用于它时,会失败。
有方法可以解决这个问题,并利用reduce。然而,鉴于直接应用min就可以完成工作,并且在我看来比任何涉及reduce的内容更加清晰明了,因此似乎没有太多意义。

2
不要使用lambda表达式,当有内置函数可以完成相同的操作时,可以使用key=operator.attrgetter('transactionDate')。 - agf
1
reduce 不起作用是因为第一次调用 reduce 的结果(一个 time.struct_time)被传递为下一次调用的参数之一。 - Duncan
1
@agf:为什么,operator.attrgetter 有显著的效率差异或者其他实际上使它更可取的东西吗? - David Z
1
reduce((lambda x,y: x if x.transactionDate < y.transactionDate else y), transactions) 相比,这个是可行的 😉 - Jochen Ritzel
1
@agf: 是的,我只是不经常使用那个效果,以至于它的语法真的无法在我的脑海中留存。而且我发现,通常情况下,为了做同样的事情,查找它的语法并不值得,因为我可以使用 lambda 函数来完成,只会带来几个百分点的性能损失。(我刚刚运行的一个测试显示有 4% 的差异) - David Z
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接