从 Prolog 中的一个列表捕获值并添加到另一个列表

Capture values from one list in Prolog and add to another list

我正在尝试在 prolog 中开发代码以捕获频率为 0 的项目。查看示例,元组:

[[1,31],[2,0],[3,21],[4,0],[5,0]]

其中每个元素都是其他元素,每个元素有 2 个元素,因此应该捕获的元素是 2、4 和 5,频率为 0。下面的代码代表了这个想法:

match([],_).
match([[A,Y]|Tail],[A|Tail2]):- Y==0,match(Tail,[Tail2|A]),!.
match([[_,_]|Tail],X):- match(Tail,X).

传递了两个参数:包含一组目标值和频率的元组,

(["Target value", "frequency"], ["target value", "frequency"], ...]

第二个参数是一个变量,它接收目标元素。但是,我开发代码时的抽象并不正确,因为结果不是预期的那样。我一步一步地理解,修改了几件事,结果总是一样的......在任何情况下都返回一个只有 2 个元素的列表(即使只有一个频率为 0 的目标)。

具有 3 个频率目标的示例 0:

?- match([[1,31],[2,0],[3,312],[4,0],[5,0]],X).
X = [2|4].

本案例的预期结果:X = [2,4,5].

具有 1 个频率目标 0 的示例:

?- match([[1,31],[2,0],[3,312],[4,312],[5,123]],X).
X = [2|_9998].

此案例的预期结果:X = [2]。

有人可以帮助我吗?

你非常接近!只是两个小问题:

  • 目前当一个空列表被传递给它时,你说结果可以是任何东西(_)。我非常怀疑这就是你想要的;空列表的输出也应该是一个空列表。
  • 第二个子句中的递归调用不正确。您想要的结果是 A 后跟递归调用的结果 (Tail2)。但是,出于某种原因,您编写了其中还包含 A 的递归调用。我不太清楚你是怎么做到的,但你应该自己得到 Tail2

另外,直接写在子句的开头就可以避免写Y==0。生成的代码如下所示:

match([],[]).
match([[A,0]|Tail], [A|Tail2]) :- match(Tail, Tail2), !.
match([[_,_]|Tail], X) :- match(Tail, X).

?- match([[1,31],[2,0],[3,312],[4,0],[5,0]],X).
X = [2, 4, 5]

?- match([[1,31],[2,0],[3,312],[4,312],[5,123]],X).
X = [2]

您可以选择像这样用 DCG 描述结果列表:

match(Pairs,ZFs) :-           % the items with frequency 0
   phrase(zeros(Pairs),ZFs).  % are described by zeros//1

zeros([]) -->                 % the empty list
   [].                        % contains no items
zeros([[I,0]|Is]) -->         % if the frequency is 0
   [I],                       % the item is in the list
   zeros(Is).                 % the same for the remaining items
zeros([[I,F]|Is]) -->         % if the frequency
   {dif(F,0)},                % is not 0, the item isn't in the list
   zeros(Is).                 % the same for the remaining items

因此,您 post 中的两个示例查询产生了所需的结果:

   ?- match([[1,31],[2,0],[3,21],[4,0],[5,0]],X).
X = [2,4,5] ? ;
no
   ?- match([[1,31],[2,0],[3,312],[4,312],[5,123]],X).
X = [2] ? ;
no