10
votes

Inverser récursivement une séquence dans le clojure

Je veux inverser une séquence dans le clojure sans utiliser la fonction inverse code> et le faire de manière récursive.

Voici ce que j'ai proposé: P>

user> (reverse-recursively '(1 2 3 4 5 6))
(6 5 4 3 2 1)
user> (reverse-recursively [1 2 3 4 5 6])
(6 5 4 3 2 1)
user> (reverse-recursively {:a 1 :b 2 :c 3})
([:c 3] [:b 2] [:a 1])


2 commentaires

Étiez-vous éventuellement tenter Ce problème 4Clojure ? :)


Non, je n'etais pas. "Inverser une chaîne récursivement" est un problème d'entrevue très courant.


7 Réponses :


27
votes
  • Vous n'avez pas besoin de compter. Il suffit d'arrêter quand la séquence restante est vide.
  • Vous ne devez pas pré-peupler le ACC , car l'entrée d'origine peut être vide (et c'est plus de code).
  • la déstructuration est cool. xxx

    comme pour boucle / recur et le ACC , vous avez besoin d'un moyen de passer autour du travail liste inversée. C'est soit boucle , soit ou ajoutez un autre paramètre à la fonction (qui est vraiment ce que la boucle est de toute façon).

    ou utilisez une fonction de commande supérieure : xxx


8 commentaires

Concernant "Utiliser une fonction de commande supérieure", consultez (Source Inverser)


RÉPEC ABORD lorsque cette fonction s'applique de la carte ({: A 1: B 2: C 3}).


Eh bien, techniquement, ma question était "inverse une séquence" non "inverser quoi que ce soit" inverse une carte ", donc je pense que ce problème ne l'excluait pas. Voici l'erreur, BTW: Clojure> (Reverse-Récursivement {: A 1: B 2}) Java.lang.unsupportedoperationException: NTH Non pris en charge sur ce type: persistaparraymap


De plus, il semble que la boucle / recur est bien sûr nécessaire pour la récursion de la queue, mais elle est considérée comme une "odeur de code" dans le clojure: Twoguysarguing.WordPress.com/2010/07/26/...


@noahz en fait, l'article dit "boucle / recur est pas une odeur de code, mais se méfie de cela". Je suppose que ce qu'ils veulent dire préfère la carte, réduire, etc. en général, mais ils ne fourniront pas toujours une solution.


La solution pour permettre à tout de travailler avec la fonction ci-dessus (par exemple, des cartes), consiste à initialiser la boucle avec (SEQ Coll) , au lieu de Coll .


FWIW (inverse-récursivement ()) retournera (nil) . Ce problème est également résolu en utilisant (SEQ Coll) , bien que je préfère ne pas déstructurer dans la boucle (qui introduit un assez inutile: comme ), mais plutôt avoir un si-let à l'intérieur de la boucle.


Le : comme tout est nécessaire pour vérifier la condition de terminaison sans introduire des problèmes nul / faux-éléments. EDIT: NVM, j'ai compris ce que vous vouliez dire. Je fais habituellement cela aussi, mais je suis sur un coup de pied destructurants ces derniers temps.



0
votes
(defn my-rev [col]
  (loop [ col col
          result []]
        (if (empty? col)
            result
            (recur (rest col) (cons (first col) result)))))
Q1.The JVM can not optimize the recursion, a recursive function that would directly and stack overflow. Therefore, in Clojure, which uses the loop/recur. So, without using a function that recur deep recursion can not be defined. (which is also used internally to recur as a function trampoline.)Q2.a recursive function by recur,   must be tail-recursive. If the normal recursive function change to tail-recursive function, so there is a need to carry about the value of a variable is required as the accumulator.

5 commentaires

L'ordre d'une séquence de carte ne change pas l'exécution. Mais la commande doit être mise en œuvre.


Je ne comprends pas ton commentaire. "La commande doit être mise en œuvre?"


@noahz, (Rev {: A 1: B 2: C 3}) -> ([[: C 3] [: B 2] [: A 1]) n'est pas nécessairement le cas. Mon résultat de Clojure1.3.0 est ([: B 2] [: C 3] [: A 1])


Ah, parce que persistatarraymap in Clojure est non ordonné comme java.util.hashmap ? C'est non intuitif.


Je connais. La carte n'est en général pas déterminée que la commande sait. Afin qu'ils aient été insérés comme indiqué dans l'exemple doivent nécessairement.



4
votes

Oui à la question 1, c'est ce que j'ai créé pour ma réponse à la Récursion Koan (je ne pouvais pas vous dire si c'était une bonne pratique de clojure ou non).

(defn recursive-reverse [coll]
    (if (empty? coll)
        []
        (conj (recursive-reverse (rest coll)) (first coll) )))


3 commentaires

Eh bien, essayez ceci: (recours récursif (Appliquer STR (SEQ (prise de 100 000 (répétez "FOO")))))


Assez juste, je viens d'arriver à la dernière partie de ce koan où la fonction factorielle déborde si vous ne le faites pas sans la construction de boucle / recurienne. Je suppose donc maintenant que je peux dire que ce n'est pas une bonne pratique :) - Bravo!


C'est vraiment élégant!



2
votes

Dans la version actuelle de Clojure, une fonction intégrée appelée RSEQ . Pour quiconque passe par.


1 commentaires

RSEQ nécessite que la séquence d'entrée soit réversible , ce qui le rend généralement inapproprié (ne fonctionne pas avec les listes , avec persistanceList < / Code>, avec Lazyseq , avec des chaînes). Il est conçu comme une optimisation des séquences pouvant être inversée en temps constant.



0
votes
(defn reverse-seq [sss]
  (if (not (empty? sss))
    (conj (reverse-seq (rest sss)) (first sss))
  )
)

0 commentaires

0
votes
(defn recursive-reverse [coll]
  (if (empty? coll)
    ()
    (concat (vector (peek coll)) (recursive-reverse (pop coll )))
  )
)
and test:
user=> (recursive-reverse [1])       
(1)
user=> (recursive-reverse [1 2 3 4 5])
(5 4 3 2 1)

0 commentaires

6
votes

Pour des salopropulseurs, il existe une autre méthode utilisant dans code>. Depuis dans des utilisations internes conj code> il peut être utilisé comme suit:

(defn reverse-list 
  "Reverse the element of alist."
  [lst]
  (into '() lst))


0 commentaires