假设我有一个类似这样的列表:
S1 = [[3,6],[1,3],[4,12],[10]]
我希望排序列表为:
S = [[1,3],[3,6],[10],[4,12]](4 <9 <10 16)
更新: 我想我想出了一个使用predsort / 3和sumlist / 2的解决方案。
mycompare(Comp, [A|C], [B|D]):-
sumlist(A, X), sumlist(B, Y),
( X < Y -> Comp = '<'
; X > Y -> Comp = '>'
; compare(Comp, [A|C], [B|D])).
predsort(mycompare, S1, S).
答案 0 :(得分:2)
为什么要使用慢速且不可移植的predsort/3
?
使用keysort/2
代替 - 它是双赢的!
每个符合ISO标准的Prolog系统提供keysort/2
- 与predsort/3
或msort/2
不同...
使用SICStus Prolog 4.3.2我们定义zss_sumsorted/2
,如下所示:
:- use_module(library(lists), [maplist/3,sumlist/2,keys_and_values/3]). :- use_module(library(types), [must_be/4]). zss_sumsorted(L0, L) :- must_be(L0, list(list(integer)), zss_sumsorted(L0,L), 1), maplist(sumlist, L0, L1), keys_and_values(L10, L1, L0), keysort(L10, L10_sorted), keys_and_values(L10_sorted, _, L).
OP给出的示例查询:
| ?- zss_sumsorted([[3,6],[1,3], [4,12],[10]], Xss).
Xss = [[1,3],[3,6],[10],[4,12]] ? ;
no
编辑: @tas建议使用非地面实例化的更多测试用例,这应该引发正确的例外 - must_be/4
提供一些帮助。
| ?- zss_sumsorted([[3,6],[1,3],[4,12],[10],[_]], Xss). ! Instantiation error in argument 1 of user:zss_sumsorted/2 ! goal: zss_sumsorted([[3,6],[1,3],[4,12],[10],[_229]],_179) | ?- zss_sumsorted([[3,6],[1,3],[4,12],[10],x], Xss). ! Type error in argument 1 of user:zss_sumsorted/2 ! expected list of an integer, but found x ! goal: zss_sumsorted([[3,6],[1,3],[4,12],[10],x],_237)
答案 1 :(得分:2)
又一个版本,基于@lurker建议的相同想法,但没有maplist / 3的优雅:
:- use_module(library(clpfd)).
:- use_module(library(pairs)).
lists_sorted(L,S) :-
lists_withsums(L,SL),
keysort(SL,SSL), % instead of msort/2
pairs_values(SSL,S).
lists_withsums([],[]).
lists_withsums([List|Ls], [Sum-List|SLs]) :-
sum(List,#=,Sum),
lists_withsums(Ls,SLs).
主要区别在于使用keysort / 2而不是msort / 2,因为后者还在排序中包含实际列表,而keysort / 2保留了具有相等总和的列表的顺序。使用msort / 2的示例查询:
?- lists_sorted([[3,6],[3,1],[1,3],[4,12],[10],[2,2],[1,3]], L).
L = [[1,3],[1,3],[2,2],[3,1],[3,6],[10],[4,12]]
与keysort / 2相同的查询:
?- lists_sorted([[3,6],[3,1],[1,3],[4,12],[10],[2,2],[1,3]], L).
L = [[3,1],[1,3],[2,2],[1,3],[3,6],[10],[4,12]]
答案 2 :(得分:1)
原始代码存在一些问题。 (1)A
和B
实际上是原始列表的子列表的头部,所以你真的想要sumlist
[A|C]
和{[B|D]
1}},而不是A
和B
。您的析取(;
)逻辑意味着compare/3
仅在X = Y
为真时才被调用。 (3)比较器用于比较列表本身,这将失败。
mycompare(Comp, [A|C], [B|D]):-
sumlist(A, X), sumlist(B, Y), % ERROR: A and B are the heads of the list *element*
% you really want sumlist([A|C], X), etc...
( X < Y -> Comp = '<' % Choosing comparator based upon sum
; X > Y -> Comp = '>' % ERROR: Your disjunction (;) will ONLY do the
% following compare if `X = Y`
; compare(Comp, [A|C], [B|D])). % ERROR: comparing two lists with comparator
<小时/> 作为另一种选择,您可以通过我的评论中暗示的方式解决问题:
S-L
,其中S
是L
的总和msort
对通过Prolog中的“自然”顺序发生的S-L
字词进行排序,并将最小的S
放在第一位S-L
排序列表映射回仅L
实现如下:
sort_by_sum(InputList, SortedList) :-
maplist(pre_sum, InputList, SumWithList),
msort(SumWithList, SumWithListSorted),
maplist(un_sum, SumWithListSorted, SortedList).
pre_sum(L, S-L) :- sumlist(L, S).
un_sum(_-L, L).
?- sort_by_sum([ [3, 6], [1, 3], [4, 12], [10] ], L).
L = [[1, 3], [3, 6], [10], [4, 12]].
这是有效的,因为Prolog将使用术语比较(请参阅文档中的@<
,@>
等)来进行排序。如果A-B
小于X-Y
,则A
这样的术语小于Y
。因此,将9-[3,6]
与10-[10]
进行比较会发现9-[3,6]
更少。将16-[4,12]
与10-[10]
进行比较会发现16-[4,12]
更大。
keysort/2
在msort/2
代替class CustomerModel {
String phoneNumber
}
interface ICustomerOwner {
CustomerModel getCustomer()
}
class CustomerRegistrationWorkflowActivity extends Activity implements ICustomerOwner {
CustomerModel getCustomer()
...
}
class CustomerContactDataFragment // fragment1 where you edit the phone number.
class CustomerRegistrationSummaryFragment // fragment5 showing all data plus submit button)
更具规范性和便携性。
答案 3 :(得分:0)
你的解决方案似乎错了:可能是
mycompare(C, A, B) :-
sumlist(A, Sa), sumlist(B, Sb),
( Sa < Sb -> C = < ; C = > ).
lol_sorted(L, S) :-
predsort(mycompare, L, S).
或者,或者:
lol_sorted(L, S) :-
setof(N-E, (member(E,L),sumlist(E,N)), R),
pairs_values(R, S).
这会松散重复的,相同的列表(不是总和)。为了保留它们,一个稍微复杂的片段:
lol_sorted(L, S) :-
setof(N/P-E, (nth0(P,L,E),sumlist(E,N)), R),
pairs_values(R, S).