SWI-Prolog:在列表中找到第二个最小值

时间:2016-07-28 15:53:43

标签: list prolog

我是Prolog的新手,我很难弄清楚如何在列表中找到包含数字和字母的第二个最小值。当它包含一个字母时,它应该显示一个错误,当它有一个数字时,它应该显示一个错误。到目前为止,我有这个,但我不知道如何开始我的代码有信......

secondMin([_]) :- 
    print("ERROR: List has fewer than two unique elements."),
    !.
secondMin(List, M2) :- 
    min_list(List, M1), 
    delete(List, M1, List1), 
    min_list(List1, M2).

输出应如下所示:

?- secondMin([17,29,11,62,37,53], M2).
M2 = 17
?- secondMin([512], M2).
ERROR: List has fewer than two unique elements.
?- secondMin([7,5.2,3,6,-3.6,9,-2], M2).
M2 = -2
?- secondMin([12,2,b,7], M2).
ERROR: "b" is not a number.
?- secondMin([3,3,3], M2).
ERROR: List has fewer than two unique elements.

1 个答案:

答案 0 :(得分:0)

最简单但最迫切的方法是使用maplist来确定是否存在任何非数字。然后使用sort获取唯一的第二分钟。

secondMin(L, M) :-
    (   maplist(number, L)
    ->  (   sort(L, [_,Second|_])
        ->  M = Second
        ;   print("List has fewer than two unique elements.")
        )
    ;   print("List has non-numeric elements")
    ).

<小时/> 正如@repeat在他的评论中所指出的,上述解决方案是“天真的”#34;从某种意义上说,虽然它为有效输入产生了正确的结果,但除了显示诊断消息之外,它没有适当的错误处理,但随后成功。

这是一个更全面的实现,当第一个参数没有按预期定义时,它会引发异常:

secondMin(L, M) :-
    (   ground(L)
    ->  (   is_list(L),
            maplist(number, L)
        ->  (   sort(L, [_,Second|_])
            ->  M = Second
            ;   throw('List has fewer than two unique elements')
            )
        ;   throw('First argument is not a list of numbers')
        )
    ;   throw(error(instantiation_error, _))
    ).