3

I'm working on a problem to flatten only one level of a list in Prolog. For example, [[1],[2,3]] would become [1,2,3], but [[1,[2]],3] would only flatten down to [1,[2],3]. I went through some other questions on the site, but none thoroughly answered this question, and I just can't get my code to work on all my test cases.


Update: the code works! Here is the eventual answer that I came to:

my_flatten([], []).
my_flatten([A|B],L) :- is_list(A), my_flatten(B,B1), !, append(A,B1,L).
my_flatten([A|B],[A|B1]) :- my_flatten(B,B1).
Guy Coder
  • 24,501
  • 8
  • 71
  • 136
Hhhhhhh
  • 33
  • 1
  • 5
  • 1
    possible duplicate of [Get elements from list of lists](http://stackoverflow.com/questions/9777077/get-elements-from-list-of-lists) – false Dec 03 '14 at 13:12
  • 1
    The best is to [use DCGs](http://stackoverflow.com/a/9787502/772868). – false Dec 03 '14 at 13:14
  • 1
    What do you mean by "works only about half the time?" – false Dec 03 '14 at 13:15
  • I mean that the test cases I presented don't work, but others do. For some--like the ones I showed in my post, it simply outputs the empty list. – Hhhhhhh Dec 03 '14 at 17:24
  • I cannot reproduce the example with "output" `[]` – false Dec 03 '14 at 17:26
  • Also, state test cases such that they are easy to copy-paste: e.g. `flat([1,[2,3]], R)` – false Dec 03 '14 at 17:28

2 Answers2

1

You need 3 simple clauses, I will show just the most complex one

flat([H|T],R) :- is_list(H), flat(T,T1), append(H,T1,R).

other two clauses are the base recursion case, and a copy as is of head to result.

You should also place a cut in the clause I've shown, otherwise on backtracking you'll get wrong results (due to firing of the clause copy as is)

CapelliC
  • 59,646
  • 5
  • 47
  • 90
  • So `flat([A,B], [1,2])` fails? – false Dec 03 '14 at 13:16
  • that is just as bad. Both A and B have to be lists. – false Dec 03 '14 at 13:40
  • 1
    @false: why ? flat([1,2],[1,2]) it's fine, I think – CapelliC Dec 03 '14 at 13:52
  • At least we can agree that `flat([[1,2],[]],[1,2])` is true. Therefore also `flat([A,B],[1,2]), A = [1,2], B = []` should succeed. – false Dec 03 '14 at 14:50
  • @CapelliC I've played with my code a bit and so far, gotten to `flat([], []). flat([H|T],R) :- is_list(H), flat(T,T1), !, append(H,T1,R). flat(H,H).` which is actually the best-working code I've gotten so far. It works in all cases I've tried except for when I input [1,[2,3]], when it just returns the same thing. Also, I believe I am allowed to assume that the input will always be a list--does that affect this? I'm sorry I'm such a noob at Prolog... – Hhhhhhh Dec 03 '14 at 22:05
  • Nevermind, my last clause was messing it up, I got it! Thank you, your answer was very helpful!! I will update my original question with what I came to that works :) – Hhhhhhh Dec 03 '14 at 22:16
0

This are the results obtained with the predicate described at the bottom. With flat_lvl predicate u can specify the desired level for flat a list.

Examples:

% Lis= [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]],
% flat_lvl(Lis, FlatLis, 2).
%
% ---> FlatLis = [e1, e2, e3, e4, e5, e6, e7, e8, e9]


% Lis= [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]],
% flat_lvl(Lis, FlatLis, 1).
%
% ---> FlatLis = [e1, e2, [e31, e32], e4, e5, e6, e7, e8, e9]


% Lis= [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]],
% flat_lvl(Lis, FlatLis, 0).
%
% ---> FlatLis = [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]]

The predicate to flat a list with a specified level is the following, so just set DeepLvl to 1:

flat_lvl([],[],_).
flat_lvl([LisH| LisT], FlatLis, DeepLvl):-
    Lvl is DeepLvl - 1, Lvl >= -1,
    (flat_lvl(LisH, FlatH, Lvl); FlatH= [LisH]),
    flat_lvl(LisT, FlatTail, DeepLvl),
    append(FlatH, FlatTail, FlatLis), !.

?- flat_lvl(List, 1).
Lospix
  • 16
  • 2