Levathian
Levathian

Reputation: 23

PROLOG store nth element of list if string is found in list

What im trying to do is:

fromHistory/2

fromHistory(HL,FL)

FL is the 3rd element of the list if the list contains the word "ate"

FL is the 4th element of the list if the list contains all the words ["you","can","have"]

The predicate is supposed to loop on a list of lists HL and if one of the lists inside contains the words above, it should append the 3rd/4th element depending on the word found to FL, else it shouldn't get anything.

?- fromHistory([[i,ate,x], [you,can,have,y]], FL).
FL = [x, y] ;
false.

?- fromHistory([[this,is,a,useless,input], [i,ate,x], [another,input],
                [another,useless,input], ["Ok"], [you,can,have,y]], FL).
FL = [x, y] ;
false.

x and y are not always at the end of the list but are the strings after ["ate"] and ["you","can","have"]

my attempt using the find version in here

find(X,Y,[X,Y|Tail]):-
   !.
find(X,Y,[_|Tail]):-
   find(X,Y,Tail).


foodFromHistory(HL1, FL):-
    flatten(HL1, HL),
    find(ate, FL1, HL),
    find([you, can, have], FL2, HL),
    FL = [FL1|FL2].

However it doesnt work with [you,can,have] and returns false, it also doesn't work on the entire list but rather on the first occurrence only.

Upvotes: 0

Views: 129

Answers (3)

Isabelle Newbie
Isabelle Newbie

Reputation: 9378

As a rule of thumb, if you need to process a list of some things element by element, first get a very clear idea of what to do for every single element (in this case, these "elements" are input phrases) and implement and test that without worrying about the whole problem yet. So:

FL is the 3rd element of the list if the list contains the word "ate"

FL is the 4th element of the list if the list contains all the words ["you","can","have"]

This isn't a very good specification, but here is one implementation you can test and tweak in isolation from the bigger problem:

input_food([_Somebody, ate, Food], Food).
input_food(Input, Food) :-
    append(_Something, [you, can, have, Food | _Rest], Input).

That is all! You have two requirements, each describing a simple pattern match on a list. The Prolog implementation can therefore be two clauses, each implementing a simple pattern match on a list.

Let's test:

?- input_food([i, ate, x], Food).
Food = x ;
false.

?- input_food([you, ate, x], Food).
Food = x ;
false.

?- input_food([ok, you, can, have, strawberries], Food).
Food = strawberries ;
false.

?- input_food([this, sentence, no, food], Food).
false.

OK, all we need to do now is to iterate over the input list and collect the foods given by input_food/2 for each input, if any. This is standard:

inputs_foods([], []).
inputs_foods([I|Is], [Food|Fs]) :-
    input_food(I, Food),
    inputs_foods(Is, Fs).
inputs_foods([I|Is], Fs) :-
    \+ input_food(I, _Food),
    inputs_foods(Is, Fs).

And it seems to mostly do what you want:

?- inputs_foods([[this,is,a,useless,input], [i,ate,x], [another,input],
                [another,useless,input], ["Ok"], [you,can,have,y]], FL).
FL = [x, y] ;
false.

Upvotes: 1

damianodamiano
damianodamiano

Reputation: 2662

A solution for your problem could be this:

solve(L,FL,FLO):-
    member("ate",L),
    \+consequent(L),
    nth1(3,L,E),
    append(FL,[E],FLO).

solve(L,FL,FLO):-
    \+member("ate",L),
    consequent(L),
    nth1(4,L,E),
    append(FL,[E],FLO).


consequent(L):-
    nth1(P,L,"you"),
    P1 is P+1,
    nth1(P1,L,"can"),
    P2 is P+2,
    nth1(P2,L,"have").

fromHistory([],L,L).
fromHistory([H|T],L,FL):-
    solve(H,L,FLO),
    fromHistory(T,FLO,FL).

So first you check if ate is into the list and you can have is not into it. Then you can find the element you want with nth/3 and append it to the list with append/3. Similar case when you find you can have into the list and ate is not into it. You have to decide what to do when you have both ate and you can have into the list. In this implementation the predicate fails.

Query:

?- fromHistory([["you","can","have","hallo","at"],["ate","str1","str2"]],["test","aa"],L).
L = ["test", "aa", "hallo", "str2"]

Upvotes: 0

bring112
bring112

Reputation: 63

I dont completely understand how the prediacte should work, what about array like [some,input,i,ate,x,some,other,input], should it append x to the list ?

You could try with making your own lists like H1 = [i,ate,X|_], and H2 = [you,can,have,Y|_], then just recursively going through members of HL and comparing them and getting your solutions unifying them with X or Y.

edit :

I've made something for the [i,ate,x], now you have to make similar approach to [you,can,have,y].

The approach is to check if the list [i,ate,X] is sublist of current member of HL, if it is we can add X to our set of FL. Check if this is what you were expecting :)

fromHistory(HL,FL) :-
    findAnswers(HL,[],FL).

findAnswers([],Answers,Answers).
findAnswers([H|HL],FL,Answers) :-
       (isSublist([i,ate,X],H) -> append(FL,[X],FL2); FL2 = FL),
       findAnswers(HL,FL2,Answers).

isSublist(SL, L) :-
    append([_,SL,_],L).

Upvotes: 0

Related Questions