将4个不同列表的元素分组

时间:2019-04-17 11:03:17

标签: list prolog

我有以下4个列表:

A= [1,2,3], 
B=[4,5,6], 
C=[7,8,9],
D=[10,11,12]

我想获取另一个列表列表,其第一个元素获取每个列表的第一个元素,第二个元素获取每个列表的第二个元素,等等。例如:

[1,2,3], [4,5,6], [7,8,9], [10,11,12] 

成为

[[1,4,7,10], [2,5,8,11],[3,6,9,12]].

我尝试使用

findall([X,Y,Z,T],(member(X,A),member(Y,B),member(Z,C),member(T,D)),ModifiedList).

但这没用。

如何在Prolog中做到这一点?

3 个答案:

答案 0 :(得分:3)

解决方案是:

% auxiliary predicate to group the first elements of
% all input lists and return the tails of the lists

group_first([], [], []).
group_first([[X| Xs]| Lists], [X| Tail], [Xs| Tails]) :-
    group_first(Lists, Tail, Tails).

% main predicate; we separate the first list from the other
% lists to take advantage of first-argument indexing

group([], []).
group([List| Lists], Groups) :-
    group(List, Lists, Groups).

group([], _, []).
group([X| Xs], Lists, [Group| Groups]) :-
    group_first([[X| Xs]| Lists], Group, Tails),
    group(Tails, Groups).

通话示例:

| ?- group([[1,2,3],[a,b,c],['A','B','C']], R).

R = [[1,a,'A'],[2,b,'B'],[3,c,'C']]
yes

为帮助您了解解决方案:

| ?- group_first([[1,2,3],[a,b,c],['A','B','C']], Group, Tails).

Group = [1,a,'A']
Tails = [[2,3],[b,c],['B','C']]
yes

答案 1 :(得分:1)

您所描述的只是转置/ 2:

?- [library(clpfd)].
true.

?- transpose([[1,2],[3,4],[5,6]],T).
T = [[1, 3, 5], [2, 4, 6]].

请注意,Paulo的回答很有趣:这是他在图书馆(yall)中的group_first / 3

group_first(A,B,C) :- maplist([U,V,Z]>>(U=[X|Xs],V=X,Z=Xs),A,B,C).

或更有效

group_first(A,B,C) :- maplist([[X|Xs],X,Xs]>>true,A,B,C).

group / 2的速度比clpfd:transpose:

快得多
?- N=100,length(M,N),maplist({N}/[R]>>length(R,N),M),time(group(M,T)).
% 20,402 inferences, 0.009 CPU in 0.009 seconds (100% CPU, 2165467 Lips)

?- N=100,length(M,N),maplist({N}/[R]>>length(R,N),M),time(transpose(M,T)).
% 30,708 inferences, 0.010 CPU in 0.010 seconds (100% CPU, 3192701 Lips)

在原始Paulo答案中仍然更好(group_first未内联):

?- N=100,length(M,N),maplist({N}/[R]>>length(R,N),M),time(group(M,T)).
% 10,302 inferences, 0.004 CPU in 0.004 seconds (100% CPU, 2513070 Lips)

并且(几乎)是可逆的:

?- group(T,[[1,2]]).
T = [[1], [2|_5420]].

似乎是对库(clpfd)进行拉取请求的理想选择...

答案 2 :(得分:0)

这是另一种方法:

?- dim(77,66,L), time((between(1,100,_), transpose(L,_), fail; true)).
% 1,577,201 inferences, 0.103 CPU in 0.104 seconds (99% CPU, 15244107 Lips)

?- dim(77,66,L), time((between(1,100,_), nifty(L,_), fail; true)).
% 521,601 inferences, 0.062 CPU in 0.063 seconds (99% CPU, 8368647 Lips)

?- dim(77,66,L), time((between(1,100,_), group(L,_), fail; true)).
% 528,300 inferences, 0.048 CPU in 0.049 seconds (98% CPU, 11105739 Lips)

它在速度上排名第二:

Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.4)

?- nifty([[1,2,3],[4,5,6]],X).
X = [[1, 4], [2, 5], [3, 6]].

?- nifty([[1,4],[2,5],[3,6]],X).
X = [[1, 2, 3], [4, 5, 6]] ;
false.

?- nifty(X,[[1,2,3],[4,5,6]]).
X = [[1, 4], [2, 5], [3, 6]] ;
false.

?- nifty(X,[[1,4],[2,5],[3,6]]).
X = [[1, 2, 3], [4, 5, 6]].

但是它是完全双向的,即使在SWI-Prolog中也是如此:

Jekejeke Prolog 3, Runtime Library 1.3.8 (23 May 2019)

?- nifty([[1,2,3],[4,5,6]], X).
X = [[1,4],[2,5],[3,6]]

?- nifty([[1,4],[2,5],[3,6]], X).
X = [[1,2,3],[4,5,6]]

?- nifty(X, [[1,2,3],[4,5,6]]).
X = [[1,4],[2,5],[3,6]]

?- nifty(X, [[1,4],[2,5],[3,6]]).
X = [[1,2,3],[4,5,6]]

如果Prolog系统像Jekejeke Prolog中那样提供及时的多参数索引,那么即使事不宜迟,它也不会留下任何选择点:

from PyQt5 import QtCore, QtGui, QtWidgets


class HeaderProxyStyle(QtWidgets.QProxyStyle):
    def drawControl(self, element, option, painter, widget=None):
        if element == QtWidgets.QStyle.CE_Header:
            option.text = ""
        super(HeaderProxyStyle, self).drawControl(
            element, option, painter, widget
        )


class LabelHeaderView(QtWidgets.QHeaderView):
    def __init__(self, parent):
        super(LabelHeaderView, self).__init__(QtCore.Qt.Horizontal, parent)
        self.m_labels = []
        self.sectionResized.connect(self.adjustPositions)
        self.sectionCountChanged.connect(self.onSectionCountChanged)
        self.parent().horizontalScrollBar().valueChanged.connect(
            self.adjustPositions
        )
        proxy_style = HeaderProxyStyle(self.style())
        self.setStyle(proxy_style)

    @QtCore.pyqtSlot()
    def onSectionCountChanged(self):
        while self.m_labels:
            label = self.m_labels.pop()
            label.deleteLater()
        for i in range(self.count()):
            label = QtWidgets.QLabel(self, alignment=QtCore.Qt.AlignCenter)
            self.m_labels.append(label)
            self.update_data()
            self.adjustPositions()

    def setModel(self, model):
        super(LabelHeaderView, self).setModel(model)
        if self.model() is not None:
            self.model().headerDataChanged.connect(self.update_data)

    def update_data(self):
        option = QtWidgets.QStyleOptionHeader()
        self.initStyleOption(option)
        for i, label in enumerate(self.m_labels):
            text = self.model().headerData(
                i, self.orientation(), QtCore.Qt.DisplayRole
            )
            label.setText(str(text))
            pal = label.palette()
            bc = self.model().headerData(
                i, self.orientation(), QtCore.Qt.BackgroundRole
            )
            if bc is None:
                bc = option.palette.brush(QtGui.QPalette.Window)
            pal.setBrush(QtGui.QPalette.Window, bc)

            fc = self.model().headerData(
                i, self.orientation(), QtCore.Qt.ForegroundRole
            )
            if fc is None:
                fc = option.palette.brush(QtGui.QPalette.ButtonText)
            pal.setBrush(QtGui.QPalette.ButtonText, fc)

            label.setPalette(pal)

            textAlignment = self.model().headerData(
                i, self.orientation(), QtCore.Qt.TextAlignmentRole
            )
            if textAlignment is None:
                textAlignment = self.defaultAlignment()
            label.setAlignment(textAlignment)

    def updateGeometries(self):
        super(LabelHeaderView, self).updateGeometries()
        self.adjustPositions()

    @QtCore.pyqtSlot()
    def adjustPositions(self):
        for index, label in enumerate(self.m_labels):
            geom = QtCore.QRect(
                self.sectionViewportPosition(index),
                0,
                self.sectionSize(index),
                self.height(),
            )
            geom.adjust(2, 0, -2, 0)
            label.setGeometry(geom)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QTableWidget(10, 10)
    header = LabelHeaderView(w)
    w.setHorizontalHeader(header)

    header_labels = []
    for i in range(w.columnCount()):
        header_label = "<sub>%s</sub><b>Header</b><sup>%s</sup>" % (i, i)
        header_labels.append(header_label)
    w.setHorizontalHeaderLabels(header_labels)

    w.resize(320, 240)
    w.show()
    sys.exit(app.exec_())