2013-02-22 3 views
9

Si j'ai une liste en Prolog telle que X = [1, 2, 3, 4], comment ajouter l'élément 5 à la fin de la liste pour avoir X = [1, 2, 3, 4, 5 ]?Prolog - comment ajouter un élément à une liste?

La fonction d'ajout a besoin de deux listes, à savoir append (A, B, C) pour obtenir A et B concaténé à la liste C.

je peux le faire avec une liste temporaire Y = [1, 2, 3, 4] et Z = [5], pour ensuite faire un append (Y, Z, X), mais je n'aime pas avoir une liste temporaire.

Les clauses de non-responsabilité habituelles s'appliquent ici - ce n'est pas un devoir et j'apprends simplement Prolog.

+1

Réponse courte: Vous ne le faites pas; vous n'avez simplement pas. – repeat

Répondre

1

Les variables dans Prolog ne peuvent être affectées qu'une seule fois. Dès que X a la valeur [1,2,3,4], il ne peut jamais avoir une autre valeur. Une variable temporaire et append/3, comme vous l'avez mentionné, est la façon de le faire.

Cela dit, vous pouvez faire un tour qui n'est probablement pas recommandé. Si X = [1,2,3,4, Y] alors vous pouvez faire Y = 5 et X a maintenant la valeur que vous voulez. Je crois que cette technique s'appelle une liste de différence.

+0

@ no-one-in-particulier Pensez aux variables Prolog en tant que variables mathématiques au lieu des emplacements de stockage. Je suis conscient que c'est un changement de paradigme majeur, mais quand vous l'aurez compris, tout ce qui se trouve dans Prolog sera assez facile (ou logique au moins). –

+0

@mndrix - bonne réponse. Cela efface pense. Donc, si je comprends bien, si je dis X = [A, B, C, D] et que plus tard assigner A = [1], B = [2], alors X = [[1], [2], C, RÉ]. Puis plus tard, si j'attribue C = [3], D = [4], alors j'ai finalement X = [[1], [2], [3], [4]] et il est fixé dans la pierre. –

+0

@NoOneinParticular oui, c'est vrai – mndrix

1

Vous vous inquiétez de la mauvaise fin du problème. Le partage de structure ne peut se faire qu'en disposant un élément au début de la liste. Cette méthode a les caractéristiques de performance que vous voulez. En raison de la façon dont les listes sont définies, lorsque vous ajoutez deux listes, la première liste entière sera copiée. Dans ce cas, ça va être toute la liste. Les déchets générés par une liste à un seul article vont évidemment être beaucoup plus petits que cela.

Si vous devez vraiment ajouter, pensez à reconstruire la liste à l'envers et à l'inverser une fois à la fin, ce qui est beaucoup moins cher, ou utilisez des listes de différences, qui permettent d'ajouter efficacement jusqu'à la fin.

+0

s (X) pour l'approche classique "double inversion, prepend item"! – repeat

4

Comme d'autres l'ont fait remarquer, vous allez être bloqué avec le problème de performance.
Mais juste comme un exercice, j'ai décidé d'essayer de créer un prédicat qui pourrait ajouter un élément à la fin d'une liste, sans utiliser append.

% add_tail(+List,+Element,-List) 
% Add the given element to the end of the list, without using the "append" predicate. 
add_tail([],X,[X]). 
add_tail([H|T],X,[H|L]):-add_tail(T,X,L). 

Je vous conseille que vous souhaitez simplement utiliser la fonction append, en fonction intégrée, il est susceptible d'être plus rapide que tout conçu manuellement.

+1

Dans le style de Benjamin Franklin: "* Ceux qui abandonneraient la rectitude essentielle pour acheter une petite performance temporaire, ne méritent ni la correction ni la performance. *" – repeat

+0

Quelle est la différence entre add_tail (X, [L1], [L2]) 'et' add_tail (X, [Y | L1], [Z | L2]) '? – tamaramaria

+0

[Head1, Head2 | Tail] supprimerait les 2 premières variables du début de la liste et placerait le reste dans une liste séparée dans la variable Tail. Donc [1,2,3,4] signifierait Head1 = [1], Head2 = [2], Tail = [3,4], signifiant par récursion que vous pouvez supprimer les éléments de devant d'une liste. L'add_tail se lit comme suit: 1. Si la première liste est vide et que X est maintenant le dernier élément de la liste de sortie, arrêtez de chercher des alternatives. 2. Prenez la première variable de l'inputList, transmettez X pour la vérification, unifiez récursivement H à l'avant de la liste de sortie lorsque 1. est vrai. 1. assure le retour en arrière. –

2

Une solution déclarative consiste à utiliser une liste de différences (comme Daniel l'a suggéré dans sa réponse). Une liste de différences obtient son nom d'être généralement représenté comme une différence entre deux listes: une liste et sa queue. Par exemple, une liste vide peut être représentée par T-T. Une liste avec les éléments 1, 2 et 3 peut être représentée par [1,2,3| T]-T (notez que (-)/2 est un opérateur infixe intégré standard). L'avantage de cette représentation est que vous pouvez ajouter un élément à une liste constante de temps en utilisant une définition unique de fait du prédicat append/3:

append(L1-T1, T1-T2, L1-T2). 

Un exemple d'utilisation:

?- append([1,2,3,4| T1]-T1, [5| T2]-T2, Result). 
T1 = [5|T2], 
Result = [1, 2, 3, 4, 5|T2]-T2. 

Si nécessaire, n'est pas difficile à convertir entre une liste "normale" et une liste de différences. Je laisse cela comme un exercice pour vous.

+1

Juste remarqué c'est une très vieille question (en temps Internet)! –

+0

s (X): solide comme une roche. – repeat

0

Vous ne pouvez pas modifier les listes en Prolog, mais vous pouvez créer une liste avec une durée indéterminée:

main :- 
    A = [1,2,3,4|_]. 

Ensuite, vous pouvez insérer un élément en utilisant nth0/3 dans SWI-Prolog:

:- initialization(main). 

main :- 
    A = [1,2,3,4|_], 
    nth0(4,A,5), 
    writeln(A). 

Une fois cet élément inséré, A = [1,2,3,4,5|_].

Vous pouvez également définir une fonction qui ajoute un élément à la fin d'une liste en place, puis l'utiliser comme ceci:

:- initialization(main). 

append_to_list(List,Item) :- 
    List = [Start|[To_add|Rest]], 
    nonvar(Start), 
    (var(To_add),To_add=Item;append_to_list([To_add|Rest],Item)). 

main :- 
    A = [1,2,3|_], 
    append_to_list(A,4), 
    append_to_list(A,4), 
    writeln(A). 

Dans cet exemple, A = [1,2,3,4,4|_] après ces deux éléments sont annexés.

0

Étant donné que Prolog a append qui n'accepte que des listes, pourquoi n'utilisons-nous pas insert notre élément dans l'une des listes. c'est-à-dire

% E = element, L = list, R = result 
% e.g. add_elem_in_list ([1,2,3,4], 5, R). 
add_elem_in_list(L, E, R) :- append(L, [E], R). 
Questions connexes