我正在尝试使用Karate Chop Kata来学习Erlang。我将kata中提供的runit测试翻译成了一个eunit测试,并编写了一个小函数来执行手头的任务。
-module(chop).
-export([chop/2]).
-import(lists).
-include_lib("eunit/include/eunit.hrl").
-ifdef(TEST).
chop_test_() -> [
?_assertMatch(-1, chop(3, [])),
?_assertMatch(-1, chop(3, [1])),
?_assertMatch(0, chop(1, [1])),
....several asserts deleted for brevity...
].
-endif.
chop(N,L) -> chop(N,L,0);
chop(_,[]) -> -1.
chop(_, [],_) -> -1;
chop(N, L, M) ->
MidIndex = length(L) div 2,
MidPoint = lists:nth(MidIndex,L),
{Left,Right} = lists:split(MidIndex,L),
case MidPoint of
_ when MidPoint < N -> chop(N,Right,M+MidIndex);
_ when MidPoint =:= N -> M+MidIndex;
_ when MidPoint > N -> chop(N,Left,M)
end.
编译确定。运行测试然后给出(以及其他)以下故障:
::error:badarg
in function erlang:length/1
called as length(1)
in call from chop:chop/3
我尝试了不同的声明斩(N,[L],M)....和使用长度([L])的排列但是无法解决这个问题。欢迎任何建议。
PS。正如你可能已经猜到的那样,当谈到Erlang时,我就是个笨蛋。
答案 0 :(得分:3)
所以我现在时间紧迫,但我看到的第一个问题是
chop(N,L) -> chop(N,L,0);
chop(_,[]) -> -1.
错误,因为chop(N,L)将始终匹配。扭转这些条款,看看它在哪里。
除此之外,在1元素列表的情况下,nth(0,[1])将失败。我觉得这些列表可能是1索引的。
答案 1 :(得分:0)
答案 2 :(得分:0)
作为最重要的学习内容你应该意识到,在erlang中使用二进制搜索列表是错误的想法,因为lists:nth/2
不是O(1)而是O(N)操作。尝试list_to_tuple/1
而不是在元组上执行。这是值得的工作。
在array
模块上尝试它也是值得的。
答案 3 :(得分:-1)
似乎结合Ben Hughes的言论解决了这个问题。为了完整起见,我将粘贴下面的二进制搜索的测试传递实现。
chop(_,[]) -> -1;
chop(N,L) ->
Array = array:from_list(L),
chop(N,Array, 0, array:size(Array)-1).
chop(N, L, K, K) ->
Element = array:get(K,L),
if
Element == N -> K;
true -> -1
end;
chop(_, _, K, M) when M < K -> -1;
chop(N, L, K, M) ->
MidIndex = K + ((M - K) div 2),
MidPoint = array:get(MidIndex,L),
case MidPoint of
N -> MidIndex;
_ when MidPoint < N -> chop(N,L,MidIndex+1,M);
_ -> chop(N,L,K,MidIndex-1)
end.