10
votes

Comment puis-je écrire le concaténate de la liste d'Erlang sans utiliser le module de listes?

Le livre que je lis sur Erlang a des exercices à l'arrière de celui-ci et il est nécessaire de recréer les listes: Ajoutez la fonction.

Je pourrais le faire simplement en utilisant l'opérateur ++, mais n'est-ce pas vraiment lent? Et je pense que le point de l'exercice est de le faire à l'aide d'opérations de liste que j'écris.

Jusqu'à présent, la seule approche que je pouvais penser est de faire quelque chose comme: xxx

mais je sais que c'est incorrect ...

Toute suggestion sur la façon de faire cela?

Edit: Pour clarifier la question, voici un Exemple d'entrée et de sortie:

entrée: [[[1,2,3], [], [4,5], [6]]] Sortie: [1,2,3,4,5,6]

Après avoir travaillé un moment, j'ai également proposé ce code: xxx

Toutefois, cela ne fonctionne que lorsque la liste est la taille 3. Comment puis-je modifier ceci afin qu'il fonctionne pour une quantité donnée de listes de taille au hasard?


5 commentaires

Je n'utilise pas Erlang, mais je ne peux pas imaginer que listes: Ajout est plus rapide que ++ (je pense que c'est O (n), quoi que ce soit ce).


Mais ++ peut être inefficace si son opérande gauche est plus grand que son bon opérande. Cette pénalité de performance a-t-elle également lieu avec des listes: appendez-vous?


Oui. Erlang fera de mieux en ce qui concerne la structure de données en question, une liste immuable à une liste localisée. À la suite de ces listes: ANNEXE ([x, Y]) est nécessairement O (longueur (x)).


Comme indiqué par @Alexeyromanov Voir le code: référentiel Erlang


erl -noshell -val 'io: fwrite ("~ p ~ n", [nom de fichier: rejoindre (lib_dir (stdlib), "src", "list.erl"])])' -S init arrêter


4 Réponses :


4
votes

Vous n'avez besoin que de deux paramètres sur votre fonction Concat, car vous allez être ajouté à l'un des paramètres et c'est ce que vous allez finalement revenir. Quelque chose comme (non testé): xxx

Le ++ est l'opérateur de l'annexe, vous allez devoir faire cela pour être efficace.

(L'idée de la ci-dessus consiste à renvoyer le paramètre de gauche si nous n'avons plus de choses à gauche, ou appelez à nouveau après avoir déplacé l'un des éléments de droite à gauche). Il y a probablement plus d'efficacité autour de faire l'annexe en sens inverse et enfin en inversant la réponse, mais hey ...)

(vient de voir votre édition, et le mien bien sûr ne fonctionne que pour deux choses à ajouter, mais vous pouvez Recurrez à travers la fonction ci-dessus pour chaque élément de votre liste de listes ...)


3 commentaires

Il n'avait pas besoin de crochets autour du H (au moins quand je l'ai couru) et travaillé assez bien! Merci!


Mais il y a plus! Sur le chemin du travail, j'ai pensé à ajouter cette clause de fonction: Concat (L, [H | T]) lorsque IS_List (H) -> Concat (Concat (L, H), T)). Et cela gérerait quelque chose comme la matrice imbriquée que vous aviez: Concat ([], [1,2,3, [1,2], [1,2, [1,2]]]). (C'est-à-dire que c'est vraiment un aplatir ...)


Cette utilisation est-elle efficace de ++? La liste de gauche en ++ est en cours de copie. erlang.org/doc/efficient_guide/listhandling.html



14
votes

++ n'est lent que lorsque vous êtes utilisé à tort, utilisé avec précaution, il est aussi rapide que tout ce que vous pouviez emprunter à la main. Vous devez vous assurer de travailler dans la liste dans la bonne direction, sinon l'annexe résultante est O (n ^ 2). Lorsque nous faisons x ++ y, nous devons effectuer une copie de x puis la préparer à Y qui n'est pas copiée.

Dans cette fonction, l'accumulateur apparaît sur le côté gauche de la ++, de sorte que l'annexe est donc à l'annexe. non efficace. xxx

Cette fonction fonctionne beaucoup mieux, même si ce n'est pas de la queue récursive. xxx

Dans ce cas de réécriture Pour être une queue récursive n'est qu'une amélioration modeste: xxx

Les timings sur une grande liste d'entrée montrent à quel point l'amélioration est énorme. (Les temps sont en microsecondes.) xxx


3 commentaires

Je lis le livre O'Reilly Erlang et je me souviens de lire que si vous souhaitez préparer un nouvel élément à la tête d'une liste, utilisez la notation des inconvénients, tels que: [H | ACC] au lieu de ++. Comment cela affecterait-il les résultats que vous avez donnés?


Utiliser | Pour prétendre un seul élément, ++ pour préparer une liste d'éléments. Autre que ce qu'ils sont identiques. [A] ++ b = [a | b]. Vous pouvez implémenter ++ en utilisant | (Assurez-vous de construire dans la bonne direction), auquel cas vous obtiendrez quelque chose du même ordre que ++, mais plus lentement, car ce n'est pas intégré.


Si vous préparez un seul élément, [A] ++ B est précisément équivalent à [A | B]. En fait, je m'attendrais à ce que le compilateur le converse au formulaire [A | B] lors de la compilation.



4
votes

Une approche soignée consiste à utiliser listes: replier , xxx

C'est aussi une bonne exercice pour écrire votre propre fonction de pli ... < / p>


0 commentaires

0
votes
    -module(functional).
    -export([my_append/2,helper/2]).

    my_append(L1,L2) ->
      % concatenates lists L1 and L2
        functional:helper(lists:reverse(L1),L2).
    helper(L1,L2) ->
        if
            L1 == [] -> L2;
            L2 == [] -> L1;
            true     -> [H1|T1] = L1,
                        functional:helper(T1,[H1|L2])
        end.

0 commentaires