【问题标题】:Length ordered subsets?长度有序子集?
【发布时间】:2015-10-23 11:45:24
【问题描述】:

我正在尝试编写一个代码,以按顺序生成集合的所有子集。 也就是说,调用subset([1,2,3], X) 应该会生成

X = [];
X = [1];
X = [2];
X = [3];
X = [1,2];
X = [1,3];
X = [2,3];
X = [1,2,3].

内部顺序并不是那么重要,只是最小的子集首先列出(即我不在乎 [2,3] 是否在 [1,2] 之前,只是 1, [2 ] 和 [3] 在 [2,3] 之前)。

--

到目前为止,我已经尝试了两种方法。首先,我尝试自己制作谓词...

subset([], []).
subset(List, []).
subset(List, [N]) :-
    member(N, List).

subset(List, [N|Rest]) :-
    !,
    nth0(I, List, N),
    findall(E, (nth0(J, List, E), J > I), NewList),
    subset2(NewList, Rest).

...但它甚至无法按预期工作。其次,我尝试制作 powerset(使用 this subset predicate)并使用 list_to_ord_set/2 进行排序,但我也无法让它工作。

帮助?

【问题讨论】:

    标签: list prolog


    【解决方案1】:

    在描述列表时也要考虑使用DCG notation

    例如:

    list_sublist(Ls0, Ls) :-
            same_length(Ls0, Ls1),
            append(Ls, _, Ls1),
            phrase(sublist(Ls0), Ls).
    
    sublist([])     --> [].
    sublist([L|Ls]) --> ( [] ; [L] ), sublist(Ls).
    

    示例查询:

    ?- list_sublist([a,b,c], Ls). 
    Ls = [] ;
    Ls = [c] ;
    Ls = [b] ;
    Ls = [a] ;
    Ls = [b, c] ;
    Ls = [a, c] ;
    Ls = [a, b] ;
    Ls = [a, b, c] ;
    false.
    

    另一个例子:

    ?- list_sublist(Ls, [b,c]).
    Ls = [b, c] ;
    Ls = [_G511, b, c] ;
    Ls = [b, _G514, c] ;
    Ls = [b, c, _G517] ;
    etc.
    

    最一般的情况:

    ?- list_sublist(Xs, Ys).
    Xs = Ys, Ys = [] ;
    Xs = [_G513],
    Ys = [] ;
    Xs = Ys, Ys = [_G513]
    Xs = [_G513, _G516],
    Ys = [] ;
    etc.
    

    【讨论】:

    • s(X):我真的很喜欢sublist//1。写( [] | [L] )而不是( [] ; [L] )怎么样?
    • 我总体上非常赞成在 DCG 中使用 |,+1!虽然当变量不完全称为L 时,它可能更具可读性,不是吗?将[] | [L] 或可读性稍差的[]|[L][] ; [L][];[L] 进行比较。因为我真的很想在这种情况下使用L,所以我发现; 在这个具体的情况下更易读。在[] | [_] 之类的情况下,我肯定会使用|
    • 有任何关于在困难阅读条件下 ASCII 字符的视觉相似性的数据吗?就像行话文件“伟大的符文”一样,但不是大写与小写,而是大写与大写。我猜当周围可能有任何“[|I_17”时,“L”是不好的(如果我们考虑使用斜体来强调某事,再加上一些)......
    • 这将非常有趣!我目前对此一无所知。
    • 肯定有一些东西!看看[_I|Is]在阅读困难的条件下...也许 UX 人员可以提供帮助:眼动追踪和皮肤电导测量,也许?
    【解决方案2】:

    我找到了一个不太优雅的解决方案......它需要一个剪辑和一些内置函数

    subset(Xs, Ys) :-
        length(Xs, L),
        between(0, L, N),
        length(Ys, N),
        assign(Xs, Ys).
    
    assign(_, []) :- !.
    assign([X|Xs], [X|Ys]) :-
        assign(Xs, Ys).
    assign([_|Xs], Ys) :-
        assign(Xs, Ys).
    

    正如@Fatalize 所说,我们可以避免删减,只需在 1^ 子句的第一个参数上强制使用空列表:

    assign([], []).
    assign([X|Xs], [X|Ys]) :-
        assign(Xs, Ys).
    assign([_|Xs], Ys) :-
        assign(Xs, Ys).
    

    我避免交换 2^ 和 3^ 子句,所以仍然很好地保留了“自然”顺序

    【讨论】:

    • 如果您使用assign([],[]). 而不是您的第一条规则,您不需要剪辑吗?如果您想摆脱由于某种原因输出false 的最后一个评估,您可以交换第二个和第三个assign 规则的顺序。它会更改顺序,但根据 OP 的要求仍然有效。
    • @Fatalize:cut 需要避免重复的解决方案,并且 anon var 接受 Xs 的子列表
    • 我不明白。通过这些更改,我获得了完全相同的结果。愿意提供一个需要剪切和匿名变量的示例吗?
    • 是的,它有效!我会把它作为公认的答案,但我会在几天后回来看看你所说的“更优雅”的东西。
    • @Fatalize:您说得对,应用您描述的更改我们会以“内部”逆序得到解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-04
    • 1970-01-01
    • 2012-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多