python – 将一个“增长”表的命令式算法转换为纯函数
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了python – 将一个“增长”表的命令式算法转换为纯函数,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3912字,纯文字阅读大概需要6分钟。
内容图文
![python – 将一个“增长”表的命令式算法转换为纯函数](/upload/InfoBanner/zyjiaocheng/770/3fc6f7a7e84446fa968c2e6dbe6d8123.jpg)
我的程序是用Python 3编写的,它有很多地方以一个(非常大的)类似数字的数据结构开始,并按照某种算法为它添加列. (每个地方的算法都不同.)
我试图将其转换为纯函数方法,因为我遇到了命令式方法的问题(难以重用,难以回忆临时步骤,难以实现“懒惰”计算,由于依赖于状态而容易出错等) .
Table类实现为字典字典:外部字典包含行,由row_id索引; inner包含一行中的值,由column_title索引.该表的方法非常简单:
# return the value at the specified row_id, column_title
get_value(self, row_id, column_title)
# return the inner dictionary representing row given by row_id
get_row(self, row_id)
# add a column new_column_title, defined by func
# func signature must be: take a row and return a value
add_column(self, new_column_title, func)
到目前为止,我只是在原始表中添加了列,每个函数都将整个表作为参数.当我转向纯函数时,我必须使所有参数都是不可变的.因此,初始表变得不可变.任何其他列都将作为独立列创建,并仅传递给需要它们的那些函数.典型的函数将采用初始表和已创建的几列,并返回一个新列.
我遇到的问题是如何实现独立列(列)?
我可以把它们都变成字典,但看起来很贵.实际上,如果我需要在每个逻辑行中的10个字段上执行操作,我将需要进行10次字典查找.最重要的是,每列将包含键和值,使其大小加倍.
我可以使Column成为一个简单的列表,并在其中存储对从row_id到数组索引的映射的引用.好处是这个映射可以在对应于同一个初始表的所有列之间共享,并且一次查找一次,它适用于所有列.但是这会产生任何其他问题吗?
如果我这样做,我可以更进一步,并实际将映射存储在初始表本身中吗?我可以将Column对象的引用放回到创建它们的初始表吗?它似乎与我想象的功能性工作方式有很大不同,但我看不出它会导致什么问题,因为一切都是不可改变的.
通常,函数方法是否会将返回值中的引用保留为其中一个参数?它似乎不会破坏任何东西(如优化或懒惰评估),因为无论如何已经知道了这个论点.但也许我错过了一些东西.
解决方法:
我将如何做到这一点:
>从frozenset中派生您的表类.
>每一行都应该是元组的一个次级.
现在你无法修改表格 – >不变,太棒了!下一步
可能是将每个函数都考虑为你应用的变异
表生成一个新表:
f T -> T'
这应该被解读为应用表T上的函数f来产生
新表T’.您也可以尝试对实际处理进行客体化
表数据并将其视为您应用或添加到的操作
表.
add(T, A) -> T'
这里最棒的是添加可以减去而不是给你
一种简单的撤消模型.当你进入这种心态时,你的代码
变得非常容易推理,因为你没有可以的状态
搞砸了.
下面是一个如何实现和处理表的示例
在Python中以纯粹的功能方式构造. Imho,Python不是
学习FP的最佳语言,因为它使它变得容易
程序势在必行.我认为Haskell,F#或Erlang是更好的选择.
class Table(frozenset):
def __new__(cls, names, rows):
return frozenset.__new__(cls, rows)
def __init__(self, names, rows):
frozenset.__init__(self, rows)
self.names = names
def add_column(rows, func):
return [row + (func(row, idx),) for (idx, row) in enumerate(rows)]
def table_process(t, (name, func)):
return Table(
t.names + (name,),
add_column(t, lambda row, idx: func(row))
)
def table_filter(t, (name, func)):
names = t.names
idx = names.index(name)
return Table(
names,
[row for row in t if func(row[idx])]
)
def table_rank(t, name):
names = t.names
idx = names.index(name)
rows = sorted(t, key = lambda row: row[idx])
return Table(
names + ('rank',),
add_column(rows, lambda row, idx: idx)
)
def table_print(t):
format_row = lambda r: ' '.join('%15s' % c for c in r)
print format_row(t.names)
print '\n'.join(format_row(row) for row in t)
if __name__ == '__main__':
from random import randint
cols = ('c1', 'c2', 'c3')
T = Table(
cols,
[tuple(randint(0, 9) for x in cols) for x in range(10)]
)
table_print(T)
# Columns to add to the table, this is a perfect fit for a
# reduce. I'd honestly use a boring for loop instead, but reduce
# is a perfect example for how in FP data and code "becomes one."
# In fact, this whole program could have been written as just one
# big reduce.
actions = [
('max', max),
('min', min),
('sum', sum),
('avg', lambda r: sum(r) / float(len(r)))
]
T = reduce(table_process, actions, T)
table_print(T)
# Ranking is different because it requires an ordering, which a
# table does not have.
T2 = table_rank(T, 'sum')
table_print(T2)
# Simple where filter: select * from T2 where c2 < 5.
T3 = table_filter(T2, ('c2', lambda c: c < 5))
table_print(T3)
内容总结
以上是互联网集市为您收集整理的python – 将一个“增长”表的命令式算法转换为纯函数全部内容,希望文章能够帮你解决python – 将一个“增长”表的命令式算法转换为纯函数所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。