99% %%_* Exports ==========================================================
1010-export ([ map /2
1111 , map /3
12+ , filtermap /2
13+ , filtermap /3
1214 ]).
1315
1416-export_type ([ opt / 0
@@ -34,6 +36,15 @@ map(F, Xs) ->
3436map (_F , [], _Opts ) ->
3537 {ok , []};
3638map (F , Xs , Opts ) ->
39+ filtermap (fun (A ) -> {true , F (A )} end , Xs , Opts ).
40+
41+ - spec filtermap (fun ((A ) -> boolean () | {true , B }), [A ]) -> maybe ([maybe (B , _ ) | B ], _ ).
42+ filtermap (F , Xs ) ->
43+ filtermap (F , Xs , []).
44+
45+ filtermap (_F , [], _Opts ) ->
46+ {ok , []};
47+ filtermap (F , Xs , Opts ) ->
3748 Timeout = s2_lists :assoc (Opts , timeout , infinity ),
3849 Errors = s2_lists :assoc (Opts , errors , false ),
3950 Workers = s2_lists :assoc (Opts , workers , 0 ),
@@ -106,7 +117,15 @@ spawn_workers(F, Xs, Workers, ChunkSize) ->
106117 [proc_lib :spawn_link (? thunk (worker (F , C , Self ))) || C <- Chunks ].
107118
108119worker (F , Chunk , Parent ) ->
109- s2_procs :send (Parent , [? lift (F (X )) || X <- Chunk ]).
120+ s2_procs :send (Parent , worker_filtermap (F , Chunk )).
121+
122+ worker_filtermap (F , [X | Chunk ]) ->
123+ case F (X ) of
124+ true -> [? lift (X ) | worker_filtermap (F , Chunk )];
125+ {true , Value } -> [? lift (Value ) | worker_filtermap (F , Chunk )];
126+ false -> worker_filtermap (F , Chunk )
127+ end ;
128+ worker_filtermap (_F , []) -> [].
110129
111130% %%_ * Chunking --------------------------------------------------------
112131chunk (Xs , Workers , ChunkSize )
@@ -136,14 +155,27 @@ divide(N, M) when N rem M =/= 0 -> N div M + 1.
136155% %%_* Tests ============================================================
137156- ifdef (TEST ).
138157
139- basic_test () ->
158+ map_basic_test () ->
140159 {ok , []} = map (fun (X ) -> X + 1 end , []),
141160 {ok , Ys } = map (fun (X ) -> X + 1 end , [0 , 1 , 2 ]),
142161 true = length (Ys ) =:= 3 ,
143162 true = lists :member (1 , Ys ),
144163 true = lists :member (2 , Ys ),
145164 true = lists :member (3 , Ys ).
146165
166+ filtermap_basic_test () ->
167+ Fun = fun
168+ (X ) when X rem 2 =:= 1 -> {true , X + 1 };
169+ (_X ) -> false
170+ end ,
171+
172+ {ok , []} = filtermap (Fun , []),
173+ {ok , Ys } = filtermap (Fun , [0 , 1 , 2 ]),
174+ true = length (Ys ) =:= 1 ,
175+ false = lists :member (1 , Ys ),
176+ true = lists :member (2 , Ys ),
177+ false = lists :member (3 , Ys ).
178+
147179timeout_test () ->
148180 {ok , []} = map (fun (X ) -> X + 1 end , [], [{timeout , 0 }]),
149181 {error , timeout } = map (fun (X ) -> X + 1 end , [0 , 1 , 2 ], [{timeout , 0 }]).
0 commit comments