Prolog,在元组列表中查找列表元素



我正在尝试用Prolog解决一个新程序,但我卡住了,不知道如何继续...我必须做一个有 3 个参数的谓词,第一个是元素列表,第二个是元组列表,第三个必须是包含元组第二个元素的列表,如果元组的第一个元素与第一个参数列表的元素匹配。它也必须删除副本!!

例如

check([a,c],[(a,aa),(bb,bbb),(a,aa),(c,def)],X).
X = [aa, def] .

如您所见,a 和 c 在元组列表中匹配,因此返回元组的第二个元素。

所以它可以工作,但是如果有多个元组包含与第一个列表匹配的第一个元素,则只需要一次,例如:

check([a,b],[(a,c),(a,d),(b,c),(b,e),(c,f)],X).
X = [c] .
它第一次找到 a 并取 c,b

第一次并再次取 c,但不迭代以找到更多的 a 或 b,正确的结果应该是 X=[c,d,e]。

所以拜托,我请你帮忙解决这种情况或任何解决它的线索......

这是我的代码:

check([],_,[]).
check(L,DIC,Xord) :- inter(L,DIC,X), list_to_set(X,Xord).
inter([],_,[]).
inter(L1, DIC, L3) :- 
   L1 = [H|T], 
   DIC = [(DIC1,DIC2)|_], 
   H == DIC1, 
   L3 = [DIC2|L3T], 
   inter(T, DIC, L3T).
inter(L1,[_|DIC],L3) :- inter(L1,DIC,L3).
inter([_|T], DIC, L3) :- inter(T, DIC, L3).

提前感谢您的时间。

为了更容易理解的版本,我提出以下建议:

:- use_module(library(lists)).
keys_dict_uniquevalues(Ks,D,UVs) :-
    keys_dict_values(Ks,D,Vs),              % Vs ... values with duplicates
    list_set(Vs,UVs).                       % UVs ... Vs deduplicated
keys_dict_values([],_D,[]).                 % No keys no values
keys_dict_values([Key|Keys],D,Vs) :-    
    key_dict_values(Key,D,Matches),         % all Matches for Key
    keys_dict_values(Keys,D,OtherVs),       % Matches for other Keys
    append(Matches,OtherVs,Vs).             % all found values in Vs
key_dict_values(_K,[],[]).                  % no mathes if dictionary empty
key_dict_values(K,[(K,V)|Pairs],[V|Vs]) :-  % Value is in list if key matches 
    key_dict_values(K,Pairs,Vs).
key_dict_values(K,[(X,_V)|Pairs],Vs) :-     % Value is not in list
    dif(K,X),                               % if key doesn't match
    key_dict_values(K,Pairs,Vs).
list_set([],[]).                            % empty list contains no duplicates
list_set([X|Xs],[X|Ys]) :-                  % head of the first list
    subtract(Xs,[X],Zs),                    % doesn't occur in Zs
    list_set(Zs,Ys).

如果你想在不使用库(列表(的情况下编写一个程序,你必须替换 keys_dict_values/3 中的目标追加/3 和 list_set/2 中的目标减去/3。在下面的示例中按 lists_appended/3 和 list_x_removed/3:

keys_dict_uniquevalues(Ks,D,UVs) :-
    keys_dict_values(Ks,D,Vs),
    list_set(Vs,UVs).
keys_dict_values([],_D,[]).
keys_dict_values([Key|Keys],D,Vs) :-
    key_dict_values(Key,D,Matches),
    keys_dict_values(Keys,D,OtherVs),
    lists_appended(Matches,OtherVs,Vs).
key_dict_values(_K,[],[]).
key_dict_values(K,[(K,V)|Pairs],[V|Vs]) :-
    key_dict_values(K,Pairs,Vs).
key_dict_values(K,[(X,_V)|Pairs],Vs) :-
    dif(K,X),
    key_dict_values(K,Pairs,Vs).
lists_appended([],L,L).
lists_appended([X|Xs],Ys,[X|Zs]) :-
    lists_appended(Xs,Ys,Zs).
list_set([],[]).
list_set([X|Xs],[X|Ys]) :-
    list_x_removed(Xs,X,Zs),
    list_set(Zs,Ys).
list_x_removed([],_X,[]).
list_x_removed([X|Xs],X,Ys) :-
    list_x_removed(Xs,X,Ys).
list_x_removed([X|Xs],Z,[X|Ys]) :-
    dif(X,Z),
    list_x_removed(Xs,Z,Ys).

上面示例中给出的查询适用于两个版本:

?- keys_dict_uniquevalues([a,c],[(a,aa),(bb,bbb),(a,aa),(c,def)],X).
X = [aa,def] ? ;
no
?- keys_dict_uniquevalues([a,b],[(a,c),(a,d),(b,c),(b,e),(c,f)],L).
L = [c,d,e] ? ;
no

@false提供的反例对两个版本都按预期失败:

?- keys_dict_uniquevalues([a,b],[(a,c),(a,d),(b,c),(b,e),(c,f)],[c,c]).
no

@false建议的不寻常用法:

   ?- keys_dict_uniquevalues([a,b],[KV1,KV2],[e]).
KV1 = KV2 = (a,e) ? ;
KV1 = (a,e),
KV2 = (b,e) ? ;
KV1 = (a,e),
KV2 = (_A,_B),
dif(b,_A),
dif(a,_A) ? ;
KV1 = (b,e),
KV2 = (a,e) ? ;
KV1 = (_A,_B),
KV2 = (a,e),
dif(b,_A),
dif(a,_A) ? ;
KV1 = KV2 = (b,e) ? ;
KV1 = (b,e),
KV2 = (_A,_B),
dif(b,_A),
dif(a,_A) ? ;
KV1 = (_A,_B),
KV2 = (b,e),
dif(b,_A),
dif(a,_A) ? ;
no

再三考虑,这种关系实际上与列表有关,因此是 DCG 的绝佳候选者:

keys_dict_uniquevalues(K,D,UVs) :-
    phrase(keys_values(K,D),Vs),
    phrase(uniques(Vs),UVs).
keys_values([],_D) -->                 % no keys no values
    [].
keys_values([K|Keys],D) -->
    key_values(K,D),                   % the values for key K
    keys_values(Keys,D).               % followed by values for other keys
key_values(_K,[]) -->                  % no values left for key _K
    [].
key_values(K,[(K2,V)|Pairs]) -->       % values for
    {dif(K,K2)},                       % different keys are not in the list
    key_values(K,Pairs).
key_values(K,[(K,V)|Pairs]) -->        % values for en equal key
    [V],                               % are in the list
    key_values(K,Pairs).
uniques([]) -->                        % the empty list has no duplicates
    [].
uniques([X|Xs]) -->
    [X],                               % X is in the list
    {phrase(list_without(Xs,X),XRs)},  % once
    uniques(XRs).
list_without([],_X) -->                % no X in the empty list
    [].
list_without([X|Xs],X) -->             % X is not in the list
    list_without(Xs,X).
list_without([Y|Ys],X) -->
    [Y],                               % Y is in the list
    {dif(X,Y)},                        % if it is different from X
    list_without(Ys,X).

我发现这个版本比我的非DCG版本更容易阅读(请参阅代码中的注释(。两个版本的界面都是相同的,因此我的上述查询在此版本中一对一工作。查询

   ?- keys_dict_uniquevalues([a,b],[KV1,KV2],[e]).

也以相反的顺序产生相同的结果。

到目前为止,你的问题陈述和你随后的解释有点矛盾。让我们看看这是否合适。

关系名称。

首先,尝试将您的问题描述为一种关系,而不是一系列操作或命令。为了更好地概述这一点,请尝试为关系找到一个不表明必须执行某些操作的名称。相反,逐个描述每个参数。您在评论中对此表示不满,指出"这只是一个名字"。当然,只是一个名字。但这就是程序员所拥有的。名字遍地。如果每个名字都是任意选择的,甚至误导你,你将有一个非常艰难的编程时间。

那么你有什么:

  1. 包含用作keys的元素的列表。请注意,keys是复数形式。在Prolog中,许多复数代表列表。

  2. 一些字典,或带有(K, V)元素的dict。实际上,在Prolog中,我们更常用(K-V),并将其称为pair,因此pairs也非常合适。但让我们坚持你的定义。

  3. 值列表。该列表没有重复项。我们可以将其称为唯一值列表,或 uvalues .

现在所有这些结合在一起就形成了一个很好的关系:

 keys_dict_uvalues(Keys, Dict, UValues)

想象一下如何使用它

在急于实际编码之前,只需想象您已经编写了它,现在您想使用它。或者:也许你会找到一个会为你写谓词的人。但是,您如何确定代码是否有效?因此,请一起收集一些测试用例。最好从地面查询开始:

?- keys_dict_uniquevalues([a,c],[(a,aa),(bb,bbb),(a,aa),(c,def)],[aa,def]).

鉴于此,我们可以通过引入变量来省略某些部分:

?- keys_dict_uniquevalues([K1,K2],[(a,aa),(bb,bbb),(a,aa),(c,def)],[aa,def]).

您期望这里有多少解决方案?我认为这只是一个。确定?在那个时候,这些考虑是非常有价值的。

但现在是编码。我经常喜欢自上而下的方法:

keys_dict_uniquevalues(Ks, KVs, Vsu) :-
   keys_dict_values(Ks, KVs, Vs),
   list_nub(Vs, Vsu).
keys_dict_values(Ks, KVs, Vs) :-
   maplist(list_pmemberv(KVs), Ks, Vs).
list_pmemberv(KVs, K, V) :-      % the first fitting K
   tmember(k_v_p_t(K,V), KVs).
k_v_p_t(K, V, (Ki, Vi), T) :-
   if_(K = Ki, ( Vi = V, T = true ), T = false).
list_nub([], []).
list_nub([E|Es], [E|Gs]) :-
   tfilter(dif(E), Es, Fs),
   list_nub(Fs, Gs).

上面使用了其他示例中定义的一些定义: maplist/3if_/3tmember/2tfilter/3(=)/3dif/3 .

以下是一些相当不寻常的例子:

具有两个条目的字典必须如何使ab都映射到e

?- keys_dict_uniquevalues([a,b],[KV1,KV2],[e]).
   KV1 = (a,e), KV2 = (b,e)
;  KV1 = (b,e), KV2 = (a,e)
;  false.

所以有两种可能性。

首先,什么

check([],_,_).

应该做的?我会放弃它。

那么,为什么要对所有内容进行排序?我会避免做无用的工作...

最后,您需要对列表进行 2 次不相关的扫描:第一个用于访问密钥,第二个用于搜索与密钥关联的值。

因此,如果不从头开始重写,您的代码就不容易更正。然后考虑内置:

check(Keys,Dict,Values) :-
  findall(V, (member(K, Keys), memberchk((K,V),Dict)), Values).
:- import append/3, member/2 from basics.
remove_duplicates([], []).
remove_duplicates([X | Y], Z) :- member(X, Y), !, remove_duplicates(Y, Z).
remove_duplicates([X | Y], [X | Z]) :- remove_duplicates(Y, Z).
hcheck(_, [], []).
hcheck(X, [(X, Y) | L], R) :- !, hcheck(X, L, RR), append([Y], RR, R).
hcheck(X, [_ | L], R) :- hcheck(X, L, R).
check([], _, []).
check([X | Y], L, R) :- hcheck(X, L, RR), check(Y, L, RRR), append(RR, RRR, RRRR), remove_duplicates(RRRR, R).
/********/
/* test */
/********/
[check loaded]
yes
| ?- check([a,c],[(a,aa),(bb,bbb),(a,aa),(c,def)],X).
X = [aa,def];
no
| ?- check([a,b],[(a,c),(a,d),(b,c),(b,e),(c,f)],X).
X = [d,c,e];
no
CHECK/hcheck

只是形成一个双循环。CHECK 从第一个列表中选择元素,而 hcheck 将元素与第二个列表中的元组匹配。结果只是附加;最后,删除重复项。我不是专家(刚学过Prolog(,所以我不知道这个解决方案有多好,但它似乎工作正常。

编辑 :

check([],_,[]).
check([X|Xs],List,[R|Rs]):-
        check_(X,List,R),
        check(Xs,List,Rs).
check_(_,[],[]).
check_(X,[(Z,Y)|Xs],Res):-
        X=Z->
        Res=[Y|Ys],
        check_(X,Xs,Ys);
        Res=Ys,
        check_(X,Xs,Ys).

测试:

    | ?- check([a,c],[(a,aa),(bb,bbb),(a,aa),(c,def)],X).
X = [[aa,aa],[def]] ? ;
no
    check([a,b],[(a,c),(a,d),(b,c),(b,e),(c,f)],X).
X = [[c,d],[c,e]] ? ;
no

最新更新