所以我需要编写一个谓词remove_duplicates/2
,从而删除给定列表中的重复元素。例如:
?- remove_duplicates([a,a,b,c,c], List).
List = [a,b,c]
Yes
请记住,我只学习SWI-Prolog两天,只了解Prolog的基础知识。这就是我现在所拥有的:
remove_duplicates([H | T], List) :-
member(H, T),
append(T, [], List1).
这适用于列表[a,a,b,c]
,但不适用于尾部中两个元素相同的列表。我想我不得不将Head删除到临时列表,创建一个新的Head并重复谓词。我不知道该怎么做。此外,当Head不在Tail中时,例如[a,b,b,c,]
之类的列表,终端只会说False
,因为member(H, T)
不是真的。
有什么想法吗?
答案 0 :(得分:8)
要删除重复项,如果订单无关紧要,最简单的方法是使用sort/2
:
?- sort([a,a,b,b,c], X).
X = [a, b, c].
?- sort([c,c,a,a,b], X).
X = [a, b, c].
当然,您会看到元素的原始顺序丢失。更重要的是,如果您正在排序的列表已经基础(其中没有自由变量),这只能保证正确。考虑这个小例子:
?- sort([X,Y], [a,a]).
X = Y, Y = a.
如果您的目标是删除重复项,那感觉不完全正确....
所以你可能也写过:
must_be(ground, List), sort(List, Unique).
您也可以自己动手,并保留原始订单。但是,你需要记录你到目前为止看到的元素。例如,您可以将它们保存在一个额外的列表中:
到目前为止看到的元素列表在开头是空的
list_unique(List, Unique) :-
list_unique_1(List, [], Us).
list_unique_1([], _, []).
list_unique_1([X|Xs], So_far, Us) :-
list_unique_2(X, Xs, So_far, Us).
如果到目前为止看到的所有元素都与X不同, 将它放在唯一元素列表中并将其添加到 到目前为止看到的元素列表。
list_unique_2(X, Xs, So_far, [X|Us]) :-
maplist(dif(X), So_far),
list_unique_1(Xs, [X|So_far], Us).
如果到目前为止看到该元素,请跳过它。
list_unique_2(X, Xs, So_far, Us) :-
memberchk(X, So_far),
list_unique_1(Xs, So_far, Us).
这是最直接的方式。还有其他更聪明的方法可能会有更好的复杂性,但这是最容易编写的。
答案 1 :(得分:3)
你的谓词存在一些问题:
remove_duplicates([H | T], List) :-
member(H, T),
append(T, [], List1).
首先你应该有一个递归谓词,你检查列表的头部但是你没有递归检查列表的尾部:
所以你可以把它改成:
remove_duplicates([H | T], List) :-
member(H, T),
remove_duplicates( T, List).
以上为尾部递归调用。
其次,如果h不是列表的成员,你必须决定会发生什么,所以你需要添加另一个子句:
remove_duplicates([H | T], [H|T1]) :-
\+member(H, T),
remove_duplicates( T, T1).
上面检查H是否存在于T中,如果不存在则强制要返回的列表的第一个元素为元素H:
如果不是很清楚,则上述内容与此相同:
remove_duplicates([H | T], List) :-
\+member(H, T),
List=[Head|Tail],
Head=H,
remove_duplicates( T, Tail).
这不是很优雅,只是了解以前的工作方式。
最后你需要为空列表递归的基础:
remove_duplicates([],[]).
因此根据上述条款的谓词remove_duplicates应为:
remove_duplicates([],[]).
remove_duplicates([H | T], List) :-
member(H, T),
remove_duplicates( T, List).
remove_duplicates([H | T], [H|T1]) :-
\+member(H, T),
remove_duplicates( T, T1).
虽然您必须注意上述内容每个元素只会保留一次,例如:
remove_duplicates([a,a,b,c],L).
L = [a, b, c] ;
false.
这没关系,但请查看以下示例:
remove_duplicates([a,a,b,a,c],L).
L = [b, a, c] ;
L = [b, a, c] ;
false.
这将返回L = [b,a,c],因为它删除了第一个' a'列表中只保留了第三个。
如果您只想删除重复项,由于成员谓词,上述内容将无效。 你可以写:
remove_duplicates2([],[]).
remove_duplicates2([H],[H]).
remove_duplicates2([H ,H| T], List) :-remove_duplicates( [H|T], List).
remove_duplicates2([H,Y | T], [H|T1]):- Y \= H,remove_duplicates( [Y|T], T1).
谓词remove_duplicates2与remove_duplicates类似,但有一些重要的区别:
1)你没有使用成员,但你检查当你有一个带有两个SAME元素的列表[H,H | T]并且你只保留一个时会发生什么,所以你忽略了第一个H并递归调用remove_duplicates2([H | T],L)。
2)如果输入[H,Y | T](列表中至少有两个元素H,Y和列表的尾部)和H \ = Y,则调用remove_duplicates2([Y | T],T1并且您已将H存储到要返回的列表中。
3)最后因为所有子句至少需要两个元素,你的递归基础是带有一个元素的列表:remove_duplicates2([H],[H])。
4)子句remove_duplicates2([],[])。仅在输入为空列表时使用,因此需要覆盖此输入。
remove_duplicates2谓词会给你:
remove_duplicates2([a,a,b,a,c],L).
L = [a, b, a, c] ;
false.
remove_duplicates2([a,a,b,c],L).
L = [a, b, c] ;
false.
答案 2 :(得分:2)
删除重复项的简单而漂亮的代码是:
remove_duplicates([], []).
remove_duplicates([Head | Tail], Result) :-
member(Head, Tail), !,
remove_duplicates(Tail, Result).
remove_duplicates([Head | Tail], [Head | Result]) :-
remove_duplicates(Tail, Result).
中所述
答案 3 :(得分:0)
您可以在此处的答案中使用list_to_set/2
或{{1}}。
答案 4 :(得分:0)
% remdup(List, List_No_duplicates).
remdup([],[]).
remdup([H|T],Lnd):- rd1(H,T,T1), remdup(T1,Tnd),Lnd=[H|Tnd].
% rd1(X,L,Lr) removes all occurance of X in List L and store result in List Lr
rd1(_,[],[]).
rd1(X,[X|T],Lx):- rd1(X,T,Lx).
rd1(X,[Y|T],Lx):- rd1(X,T,Lx1),Lx=[Y|Lx1].
它如何工作-谓词remdup
取给定List的第一个元素H并删除其在Tail部分T中出现的所有内容-将结果存储在List T1中;和
在Tnd的T1存储结果上递归调用remdup;和
将元素H添加回Tnd中,该元素实际上是通过remdup的递归调用修改的尾部T,因此已经没有所有重复项,并且不包含任何H。
谓词-rd1
答案 5 :(得分:0)
尝试一下,希望对您有所帮助
@Async
@Service
public class CustomerAsyncService {
private CustomerRepository customerRepository;
@Autowired
public CustomerAsyncService(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
@Transactional(readOnly = true, isolation = Isolation.SERIALIZABLE)
public ListenableFuture<Page<Customer>> findAll(Pageable pageable) {
return AsyncResult.forValue(customerRepository.findAll(pageable));
}
在第二个谓词中,我们验证头变量*(H)*是否在列表*(T)*的尾部。如果是的话,我们将调用第一个谓词,该谓词将删除所有等于尾部的head变量的变量,依此类推。