我想整理这样的列表:
[[[a,b],[b,c],[c,d],..]-> [a,b,c ..]
简而言之,我想把每个段[a,b]的标题放在一个扁平化的列表中。
我有当前代码:
%unsplits a list from segments
%e.g [[a,b],[b,c]] becomes [a,b,c].
unSplitList([],_).
unSplitList([[H,_]|T], L) :- append([H], L1, L), unSplitList(T, L1).
但这给了我以下输出:
?- unSplitList([[a,b],[b,c],[c,d]],L).
L = [a, b, c|_1046].
我将如何继续去除那条尾巴(_1046)?在此先感谢:)。
答案 0 :(得分:3)
这里的问题是下划线:
unSplitList([],_).
这意味着您在“ fly”上构建的列表不以[]
结尾,因此保持开放状态。
您可以通过以下方式解决此问题:
unSplitList([], []).
话虽如此,上述内容可以在优雅和效率方面有所改进。在这里,我们可以将append([H], L1, L)
替换为L = [H|L1]
,所以
unSplitList([],[]).
unSplitList([[H,_]|T], [H|L1]) :-
unSplitList(T, L1).
我们还可以通过用maplist/3
[swi-doc]来写上面的内容来改进上面的内容:
head([H|_], H).
unSplitList(L, Hs) :-
maplist(head, L, Hs).
请注意,对于包含空子列表(或数字等其他对象)的列表,以上内容无效。
答案 1 :(得分:3)
除了@WillemVanOnsem优美的基于maplist / 3的解决方案之外,我还想指出使用DCG描述磁头列表的可能性。
If cell.HasFormula Then
If cell.HasArray Then
cell.Offset(0, 1).FormulaArray = "=(" & Right$(cell.FormulaArray, Len(cell.FormulaArray) - 1) & ")/1000"
Else
cell.Offset(0, 1).Formula = "=(" & Right$(cell.Formula, Len(cell.Formula) - 1) & ")/1000"
End If
ElseIf IsNumeric(cell.Value2) Then
cell.Offset(0, 1).Value2 = cell.Value2 / 1000
End If
此DCG版本与基于Willem的Maplist / 3版本的答案相同:
lists_heads(Ls,Hs) :- % the list of heads, HS, of the lists in Ls
phrase(heads(Ls),Hs). % is described by the DCG heads//1
heads([]) --> % if there are no lists
[]. % there are no heads
heads([L|Ls]) --> % if L is the first list in the list of lists
head(L), % its head is in the list of heads
heads(Ls). % followed by the heads of the other lists
head([H|_]) --> % the head H of the list
[H]. % is in the list of heads
正如Willem所指出的,只有当第一个参数不包含空列表时,这些谓词才起作用。您可以轻松地修改DCG head // 1来解决这种情况。出于比较的原因,我将修改后的版本命名为lists_heads2 / 2,仅注释其他DCG规则:
?- lists_heads([[a,b],[b,c],[c,d]],L).
L = [a,b,c]
?- unSplitList([[a,b],[b,c],[c,d]],L).
L = [a,b,c]
?- lists_heads([[a,b,c],[b,c],[c,d]],L).
L = [a,b,c]
?- unSplitList([[a,b,c],[b,c],[c,d]],L).
L = [a,b,c]
?- lists_heads(Ls,[a,b,c]).
Ls = [[a|_A],[b|_B],[c|_C]] ? ;
no
?- unSplitList(Ls,[a,b,c]).
Ls = [[a|_A],[b|_B],[c|_C]]
以下查询说明了两个版本之间的区别:
lists_heads2(Ls,Hs) :-
phrase(heads2(Ls),Hs).
heads2([]) -->
[].
heads2([L|Ls]) -->
head2(L),
heads2(Ls).
head2([]) --> % if the list is empty
[]. % it contributes no element to the list of heads
head2([H|_]) -->
[H].
但是,这种额外的灵活性的代价乍一看可能并不明显:由于第一个参数可以包含任意数量的空列表,因此如果在另一个方向上使用,则list_heads2 / 2将循环:
?- lists_heads([[],[a,b,c],[],[b,c],[c,d]],L).
no
?- lists_heads2([[],[a,b,c],[],[b,c],[c,d]],L).
L = [a,b,c]
为了避免这种情况,如果您在此方向上使用谓词,则必须限制第一个列表的长度:
?- lists_heads(Ls,[a,b,c]).
Ls = [[a|_A],[b|_B],[c|_C]] ? ;
no
?- lists_heads2(Ls,[a,b,c]).
... % <- loops infinitely