使用Erlang实现一个迭代器iterator

本文介绍了一个使用Erlang实现的迭代器模块,该模块能够处理来自不同来源的数据流,如本地磁盘、内存或NFS等。作者通过自定义迭代器接口,实现了数据的前后遍历,并增加了折叠函数等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近比较忙, 一来是在努力学习Erlang, 二来是恋恋不舍那几个开源的小项目,三来是熟悉亲爱的R13A...
加上令人头疼的公司的事情, 导致我很忙... 哎...

为了保持博客的新鲜度, 就贴一点充数的资料吧..呵呵...

在我前段时间搞的一个开源的mapreduce小框架中, 对于map, reduce数据流的读取, 我抽象出一个迭代器, 进行数据的读取.

这样我的数据无论来自local Disk, 来自memory, 来时NFS都一视同仁...

在写一个module之前,我先想象其接口及用法:
%%% usage:
%%% Iter = make_iter(prev_fun, next_fun, State),
%%% {Next , Iter2} = next(Iter),
%%% {Next2, Iter3} = next(Iter2),
%%% {Next, Iter2} = prev(Iter3).


我们首先通过调用make_iter/3 构建一个迭代器, 第一个参数是一个函数用来获取前一条记录, 第二个参数用来获取下一条
记录. State是一个内部状态信息, 用来保存当前的状态.
构造好iter后, 我们可以通过调用prev/1, next/1 来遍历这个Iter.

这个实现,有点OO的感觉在里面, Iter可以理解为一个对象,其State为内部数据, prev_fun, next_fun为对应的方法.

为了让我们的iter模块更丰富,我们仿照lists module, 加入了foldl/3 和 foldr/3 两个函数.

当然还可以让这个iter功能更强大,比如是否可以循环迭代?是否可以双向或单向迭代?等等.有兴趣朋友可以实现哦.

好了,贴上代码:

-module(heng_iter).
-author('litaocheng@gmail.com').
-vsn('0.1').
-include("heng_master.hrl").

-export([make_iter/3]).
-export([next/1, prev/1]).
-export([foldl/3, foldr/3]).

-record(iter,
{
%type = normal :: 'normal' | 'cyclic', %
next = nil :: 'nil' | fun(),
prev = nil :: 'nil' | fun(),
state
}).

%% @doc get the next item
next(#iter{next = nil}) ->
{error, edirection};
next(Iter = #iter{next = Next, state = State}) ->
case Next(State) of
nil -> % to the end
{nil, Iter};
{V, State2} ->
{{value, V}, Iter#iter{state = State2}}
end.

%% @doc get the item in the backward
prev(#iter{prev = nil}) ->
{error, edirection};
prev(Iter = #iter{prev = Prev, state = State}) ->
case Prev(State) of
nil -> % to the end
{nil, Iter};
{V, State2} ->
{{value, V}, Iter#iter{state = State2}}
end.

%-spec foldl(Fun :: fun(), Acc :: term(), Iter :: iter()) ->
% term().
foldl(Fun, Acc, Iter) when is_function(Fun, 2) ->
{V, Iter2} = next(Iter),
foldl0(Fun, Acc, V, Iter2).

foldl0(_Fun, Acc, nil, _Iter) ->
Acc;
foldl0(Fun, Acc, {value, V}, Iter) ->
Acc2 = Fun(V, Acc),
{V2, Iter2} = next(Iter),
foldl0(Fun, Acc2, V2, Iter2).

foldr(Fun, Acc, Iter) when is_function(Fun, 2) ->
{V, Iter2} = prev(Iter),
foldr0(Fun, Acc, V, Iter2).

foldr0(_Fun, Acc, nil, _Iter) ->
Acc;
foldr0(Fun, Acc, {value, V}, Iter) ->
Acc2 = Fun(V, Acc),
{V2, Iter2} = prev(Iter),
foldr0(Fun, Acc2, V2, Iter2).

%% @doc 'fward' equal 'forward' , 'bid' equal 'bidirectional'
make_iter(Next, Prev, State)
when is_function(Next) andalso is_function(Prev)
%andalso ((Type =:= 'normal') or (Type =:= 'cyclic'))
->
#iter{%type = Type,
next = Next,
prev = Prev,
state = State
}.



最后是一个小例子, 我们定义一个迭代器,用来访问list, 当然这个做法似乎有点多此一举..
(这段代码摘自 iter 模块中的测试代码 )

%% @doc some test
basic_test_() ->
Data = ["begin", "one", "two", "there", "four", "end"],
ExpR1 = "begin one two there four end",
ExpR2 = "end four three two one begin",
%% 定义一个迭代器, 其调用listnext/1 获取下一条记录, 调用listprev/1 获取上一条记录, State为一个tuple
%% 分别保存:数据的begin, last, length 和具体的数据(也就是list)
Iter = make_iter(fun listnext/1, fun listprev/1, {0, 0, length(Data), Data}),
R =
?MODULE:foldl(fun(Str, Acc) ->
[Str, $ | Acc]
end,
[],
Iter),
Str = lists:flatten(lists:reverse(R)), % Str 为 ExpR1

Iter2 = make_iter(fun listnext/1, fun listprev/1, {length(Data)+1, 1, length(Data), Data}),
R2 =
?MODULE:foldr(fun(E, Acc) ->
[E, $ | Acc]
end,
[],
Iter2),
Str2 = lists:flatten(lists:reverse(R2)), % Str 为 ExpR2
[
?_assert(Str = ExpR1),
?_assert(Str2 = ExpR2)
].

%% 用来获取下一条记录
listnext({Last, _First, Last, _Data}) ->
nil;
listnext({Pos, First, Last, Data}) ->
Pos2 = Pos + 1,
V = lists:nth(Pos2, Data),
{V, {Pos2, First, Last, Data}}.

%% 用来获取前一条记录
listprev({0, _First, _Last, _Data}) ->
nil;
listprev({First, First, _Last, _Data}) ->
nil;
listprev({Pos, First, Last, Data}) ->
Pos2 = Pos - 1,
V = lists:nth(Pos2, Data),
{V, {Pos2, First, Last, Data}}.


好了就是这些, 有了这个module, 在mapreduce框架中,用户可以自定义各种的iter 实现, map, reduce会依据用户的iter
进行具体的数据读取,然后进行处理..

详细的代码, 请参考此处:
[url]http://code.google.com/p/heng/source/browse/trunk/master/heng_iter.erl[/url]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值