Erlang“case”子句用于范围中的值

时间:2016-09-13 03:53:23

标签: algorithm optimization erlang

学习Erlang,我正在解决一个简单的问题,我想出了这个解决方案:

%%%------------------------------------------------------------------
%%% @doc https://leetcode.com/problems/add-two-numbers/
%%%
%%% @end
%%%------------------------------------------------------------------
-module(add_two_numbers).

-define(BASE10, 10).

-export([main/2]).

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

-spec main(L1 :: nonempty_list(non_neg_integer()), L2 :: nonempty_list(non_neg_integer())) -> list().

%%%==================================================================
%%% Export
%%%==================================================================
main(L1, L2) ->
  loop(L1, L2, 0, []).

-ifdef(TEST).
main_test() ->
  ?assertEqual([0, 2, 1, 2, 1, 1], add_two_numbers:main([9, 6, 9, 5, 9], [1, 5, 1, 6, 1])),
  ?assertEqual([3, 6, 9, 7, 5], add_two_numbers:main([4, 1, 8, 7, 2], [9, 4, 1, 0, 3])),
  ?assertEqual([6, 7, 9, 0, 1], add_two_numbers:main([2, 2, 3, 3], [4, 5, 6, 7])),
  ?assertEqual([6, 3, 7, 4, 1], add_two_numbers:main([4, 1, 0, 8], [2, 2, 7, 6])),
  ?assertEqual([2, 7, 9, 1], add_two_numbers:main([2, 7, 1, 0], [0, 0, 8, 1])),
  ?assertEqual([8, 9, 9, 1], add_two_numbers:main([9, 9, 9], [9, 9, 9])),
  ?assertEqual([7, 1, 6, 1], add_two_numbers:main([9, 3, 7], [8, 7, 8])),
  ?assertEqual([3, 5, 6, 1], add_two_numbers:main([6, 6, 6], [7, 8, 9])),
  ?assertEqual([0, 0, 0], add_two_numbers:main([0, 0, 0], [0, 0, 0])),
  ?assertEqual([7, 0, 8], add_two_numbers:main([2, 4, 3], [5, 6, 4])),
  ?assertEqual([0, 2, 2], add_two_numbers:main([0, 1], [0, 1, 2])),
  ?assertEqual([0, 1, 1], add_two_numbers:main([4, 6], [6, 4])),
  ?assertEqual([0, 0, 1], add_two_numbers:main([1], [9, 9])),
  ?assertEqual([0, 1], add_two_numbers:main([], [0, 1])),
  ?assertEqual([], add_two_numbers:main([], [])),

  ?assertError(badarith, add_two_numbers:main([0, 1, 2], ["", 5, 6])).
-endif.

%%%==================================================================
%%% Internal
%%%==================================================================
loop([H1 | T1], [H2 | T2], C, R) when H1 + H2 + C >= ?BASE10 ->
  loop(T1, T2, 1, R ++ [H1 + H2 + C - ?BASE10]);
loop([], [H | T], C, R) when H + C >= ?BASE10 ->
  loop([], T, 1, R ++ [H + C - ?BASE10]);
loop([H | T], [], C, R) when H + C >= ?BASE10 ->
  loop([], T, 1, R ++ [H + C - ?BASE10]);
loop([H1 | T1], [H2 | T2], C, R) ->
  loop(T1, T2, 0, R ++ [H1 + H2 + C]);
loop([], [H | T], C, R) ->
  loop([], T, 0, R ++ [H + C]);
loop([H | T], [], C, R) ->
  loop([], T, 1, R ++ [H + C]);
loop([], [], C, R) when C > 0 -> R ++ [C];
loop([], [], _, R) -> R.

困扰我的是我必须定义多少loop个电话。最终可能会有更好的解决方案。

我的问题:如果某个条件在某个范围内,我可以用case - of告诉我吗?像这样的东西,例如:

X = H1 + H2 + C,
case X of
  X >= 10 -> blah;
  _ -> ummm
end.

更新

这就是我想要实现的目标:

loop([H1 | T1], [H2 | T2], C, R) ->
  case H1 + H2 + C >= ?BASE10 of
    true -> loop(T1, T2, 1, R ++ [H1 + H2 + C - ?BASE10]);
    false -> loop(T1, T2, 0, R ++ [H1 + H2 + C])
  end;
loop([], [H | T], C, R) ->
  case H + C >= ?BASE10 of
    true -> loop([], T, 1, R ++ [H + C - ?BASE10]);
    false -> loop([], T, 0, R ++ [H + C])
  end;
loop([H | T], [], C, R) ->
  case H + C >= ?BASE10 of
    true -> loop(T, [], 1, R ++ [H + C - ?BASE10]);
    false -> loop(T, [], 0, R ++ [H + C])
  end;
loop([], [], C, R) ->
  case C > 0 of
    true -> R ++ [C];
    false -> R
  end.

......不确定它是否更好。

2 个答案:

答案 0 :(得分:2)

你可以使用这个小技巧

SELECT d.datname AS Name,  pg_catalog.pg_get_userbyid(d.datdba) AS Owner,
    CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')
        THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))
        ELSE 'No Access'
    END AS SIZE
FROM pg_catalog.pg_database d
    ORDER BY
    CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')
        THEN pg_catalog.pg_database_size(d.datname)
        ELSE NULL
    END DESC -- nulls first
    LIMIT 20

注意我不使用loop([], [], 0, R) -> lists:reverse(R); loop([], [], 1, R) -> lists:reverse(R, [1]); loop([], L2, C, R) -> loop([0], L2, C, R); loop(L1, [], C, R) -> loop(L1, [0], C, R); loop([H1 | T1], [H2 | T2], C, R) -> case H1 + H2 + C of S when S >= ?BASE10 -> loop(T1, T2, 1, [S - ?BASE10 | R]); S -> loop(T1, T2, 0, [S | R]) end. 模式,因为它是坏习惯使它成为O(N ^ 2)(见[1])。从性能的角度来看,如果必须使用Acc++[X],则不需要尾部调用优化,因此这个非尾部调用版本应该与尾部调用优化一样快,或者在某些平台上更快:

lists:reverse/1,2

或者您可以更进一步,删除案例并获取main(L1, L2) -> loop(L1, L2, 0). loop([], [], 0) -> []; loop([], [], 1) -> [1]; loop([], L2, C) -> loop([0], L2, C); loop(L1, [], C) -> loop(L1, [0], C); loop([H1 | T1], [H2 | T2], C) -> case H1 + H2 + C of X when X >= ?BASE10 -> [ X - ?BASE10 | loop(T1, T2, 1) ]; X -> [ X | loop(T1, T2, 0) ] end.

+ 0

[1]:尝试使用您的代码loop([], [], 0) -> []; loop([], [], 1) -> [1]; loop([], [H | T], C) -> loop_([], T, H + C); loop([H | T], [], C) -> loop_([], T, H + C); loop([H1 | T1], [H2 | T2], C) -> loop_(T1, T2, H1 + H2 + C). loop_(L1, L2, S) when S >= ?BASE10 -> [ S - ?BASE10 | loop(L1, L2, 1) ]; loop_(L1, L2, S) -> [ S | loop(L1, L2, 0) ]. 。在我的代码中,它需要3.5毫秒,而你的需要33秒。

答案 1 :(得分:1)

您可以使用2个辅助函数(不确定它是否更高效,可能更容易阅读):

loop([H1 | T1], [H2 | T2], C, R) ->
  N = H1 + H2 + C,
  loop(T1, T2, carry(N), R ++ sum(N));
loop([], [H | T], C, R) ->
  N = H + C,
  loop([], T, carry(N), R ++ sum(N));
loop([H | T], [], C, R) ->
  N = H + C,
  loop(T, [], carry(N), R ++ sum(N));
loop([], [], 0, R) ->
  R;
loop([], [], C, R) ->
  R ++ [C].

carry(N) when N >= ?BASE10 -> 1;
carry(_) -> 0.

sum(N) when N >= ?BASE10 -> [N - ?BASE10];
sum(N) -> [N].