2016-09-29 1 views
0

Comment puis-je déplacer une plage dans ClojureScript?Décaler une gamme dans ClojureScript?

Par exemple, disons que nous avons la gamme:

(range 3) 

Ce qui donne: (0 1 2)

Je suis à la recherche d'une fonction de décaler les valeurs vers la gauche comme ceci: (1 2 0) ou comme celui-ci (2 0 1)

Je suis venu avec une implémentation que je partagerai en guise de réponse. Je suppose que devrait être une fonction intégrée pour le faire? Mais je n'ai rien trouvé.

Répondre

2

Ceci est la fonction que j'ai écrit:

(defn <-range [n l] 
    (concat (drop n (range l)) (range n))) 

Une brève explication:

  • (range l) créer une gamme de longueur l
  • (drop n) goutte n éléments
  • (range n) créer une nouvelle gamme jusqu'à n
  • (concat) concat les deux gammes

Si je tente:

  • (<-range 0 4) donne (0 1 2 3)
  • (<-range 2 4) donne (2 3 0 1)
  • (<-range 4 4) donne (0 1 2 3)
1

J'ai inversé l'ordre de votre args, car cela se sent plus proche de la façon dont range args travail. lazy-cat est probablement préférable à concat, car il n'évaluera même pas la seconde range jusqu'à ce que ce soit nécessaire.

(defn <-range [length start-index] 
    (lazy-cat (range start-index length) 
      (range start-index))) 
+0

Nice. Le * lazyness * ne fonctionne que si une fonction comme 'take' est appelée avant' <-range' ou aussi sans 'take'? – Marcs

+0

Ouais, il va suivre toutes les règles de la paresse standard. –

1

il y a aussi une fonction cycle, que (sans surprise) cycles une collection (pour éviter la concaténation):

user> (defn <-range [n l] 
     (->> (range l) 
      cycle 
      (drop n) 
      (take l))) 
#'user/<-range 

user> (<-range 0 4) 
(0 1 2 3) 

user> (<-range 2 4) 
(2 3 0 1) 

user> (<-range 4 4) 
(0 1 2 3) 

vous pouvez aussi le faire même sans appel à range, sur la base reste:

user> (defn <-range [n l] 
     (take l (iterate #(rem (inc %) l) (rem n l)))) 

ou comme ceci:

user> (defn <-range [n l] 
     (map #(rem (+ % n) l) (range l))) 
+0

Je voulais aussi utiliser 'cycle' mais je n'ai pas réussi à trouver un algorithme, sympa! J'ai fait un petit banc d'essai avec LightTable pour trouver dans une gamme '1000000' décalée de' 5000' dont l'une est la plus rapide. Je pensais que vos fonctions seraient plus rapides que d'utiliser 'concat' ou' lazy-cat' mais il semblerait qu'elles soient de 200ms à 300ms plus lentes. Cela m'a surpris ... Au lieu de "concat" ou "paresseux" sont la plupart du temps dans les mêmes moments autour de 2800-3000ms sur Chrome. – Marcs

1

Je suppose que le range a juste été utilisé comme exemple et vous voulez vraiment pouvoir le faire à n'importe quelle collection.

(defn rotate-left [c] 
    (lazy-cat (drop 1 c) (take 1 c))) 

ou avec la possibilité de spécifier éventuellement plus de 1 rotation,

(defn rotate-left 
    ([c] (rot-left 1 c)) 
    ([n c] (lazy-cat (drop n c) (take n c)))) 

En utilisant ceci, (rotate-left (range 3)) rendements (1, 2, 0) et (rotate-left 2 (range 3)) rendements (2, 0, 1)