假设我有一些元素的数组。每个元素都有一些属性。
我需要从谓词确定的某些值子集中筛选此列表。这个子集当然可以有交叉点。 我还需要确定每个这样的子集中的值的数量。
因此,使用命令式方法,我可以编写类似的代码,它的运行时间为2 * n。复制数组的一次迭代和另一次迭代来计算子集大小。
from split import import groupby
a = [{'some_number': i, 'some_time': str(i) + '0:00:00'} for i in range(10)]
# imperative style
wrong_number_count = 0
wrong_time_count = 0
for item in a[:]:
if predicate1(item):
delete_original(item, a)
wrong_number_count += 1
if predicate2(item):
delete_original(item, a)
wrong_time_count += 1
update_some_data(item)
do_something_with_filtered(a)
def do_something_with_filtered(a, c1, c2):
print('filtered a {}'.format(a))
print('{} items had wrong number'.format(c1))
print('{} items had wrong time'.format(c2))
def predicate1(x):
return x['some_number'] < 3
def predicate2(x):
return x['some_time'] < '50:00:00'
不知何故,我无法想象在Python中以相同的运行时间以功能方式执行此操作的方法。 所以在功能风格上我可能多次使用groupby或者为每个谓词编写一个理解,但这显然比命令式方法慢。
我认为使用Stream Fusion在Haskell中可能有这样的事情(我是对的吗?) 但是在Python中怎么做?
答案 0 :(得分:0)
是的,Haskell中的融合通常会将写入两次传递的内容转换为单次传递。虽然在列表的情况下,它实际上是折叠/构建融合而不是流融合。
但是,在不强制执行纯度的语言中,这通常是不可能的。当涉及副作用时,将多个通道融合为一个不再正确。如果每次传球都输出了怎么办?未融合,您将分别获得每个传递的所有输出。融合,你得到两个传递交错的输出。如果您承诺只使用纯函数,那么可以在Python中编写融合式框架,该框架将正常工作。但我很怀疑此刻存在这样的事情。 (不过,我很想被证明是错的。)
答案 1 :(得分:0)
Python以其迭代器的形式对“流处理”提供了强有力的支持 - 而且你要求seens只是微不足道。您只需要有一种方法可以将谓词和属性分组到它 - 它可以是一个字典,其中谓词本身就是键。
也就是说,一个简单的迭代器函数接收你的谓词数据结构,以及要处理的数据可以做你想要的。迭代器会产生使用谓词信息更改数据结构的副作用。如果你想要“纯函数”,你只需要复制谓词信息,并且可能为每个元素传递和检索所有谓词和计数器值到迭代器(通过send
方法) - 我不需要认为这样的纯粹主义是值得的。
那说你可以随身携带你的代码:
from collections import OrderedDict
def predicate1(...):
...
...
def preticateN(...):
...
def do_something_with_filtered(item):
...
def multifilter(data, predicates):
for item in data:
for predicate in predicates:
if predicate(item):
predicates[predicate] += 1
break
else:
yield item
def do_it(data):
predicates = OrderedDict([(predicate1, 0), ..., (predicateN, 0) ])
for item in multifilter(data, predicates):
do_something_with_filtered(item)
for predicate, value in predicates.items():
print("{} filtered out {} items".format(predicate.__name__, value)
a = ...
do_it(a)
(如果你必须为所有谓词计算一个项失败,那么从“break”语句到状态标志变量的明显变化就足够了)