1

I am trying to find a method to implement Partition (with [] padding) in clojure. I think it's doable using loop and recur and mapping it into the list:

 (defn collect-h [v n]
   (loop [i n
          res []
          lst v
          ]
     (if (= 0 i)
       res
       (recur (dec i) (cons (first lst) res) (next lst))
       )
     )
   )

So the problem is that implementation only works on the first series of answer "(collect-h [1 2 3 4 5 6 7 8 9 10] 3) will give ((1 2 3))". So I need to map it to the whole collection and remove the first n number in every loop, but that doesn't look really efficient. I wonder if there is a better way to solve it.

Edit:

so it should work like this:

(collect-h [1 2 3 4 5 6 7 8 9 10] 3)                   ;; ((1 2 3) (4 5 6) (7 8 9) (10))

which is same to

(partition 3 3 [] [1 2 3 4 5 6 7 8 9 10])
8
  • Can you give an example of it's use? Specifically, what you want to put into it and what you want it to return. Commented Mar 24, 2016 at 4:01
  • @Mike my bad. I edited the question. Commented Mar 24, 2016 at 4:04
  • 1
    There is a core function partition-all that seems to do exactly what you want... are you trying to implement it? look at the source code? github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/… Commented Mar 24, 2016 at 4:05
  • As per @TimothyPratley there is the source code. Or you could just (defn collect-h [coll n] (partition n n [] coll)) ? Commented Mar 24, 2016 at 4:08
  • 1
    Oh, I see. Well I think we will be hard pressed to make a better version than the Clojure implementation, but I'll give it a shot! Sounds like fun. Commented Mar 24, 2016 at 4:36

3 Answers 3

5

@Timothy-Pratley answer is nice, but it is not tail recursive, meaning that it would cause stack overflow in case of large collection. Here is non stack consuming variant:

(defn my-partition [n items]
  (loop [res [] items items]
    (if (empty? items)
      res
      (recur (conj res (take n items))
             (drop n items)))))

user> (my-partition 3 (range 10))
[(0 1 2) (3 4 5) (6 7 8) (9)]
Sign up to request clarification or add additional context in comments.

Comments

3

Building off @Timothy-Pratley and the Clojure source code, you could also use lazy-seq:

(defn partition-ghetto [n xs]
  (lazy-seq (when-let [s (seq xs)]
              (cons (take n s) (partition-ghetto n (drop n s))))))

2 Comments

Whoops, I just blindly copied your answer at that bit instead of updating the reference. I've corrected it now.
Nice! I especially like that this version is so concise. Very elegant and more Clojury.
2

How about this?

(defn partition-ghetto [n xs]
  (if (seq xs)
    (cons (take n xs) (partition-ghetto n (drop n xs)))
    ()))

(partition-ghetto 3 (range 10))
=> ((0 1 2) (3 4 5) (6 7 8) (9))

Definitely not as good as the core version, but might provide some ideas?

Note that this recursive definition is not tail recursive, so will blow the stack for large sequences, nor is it lazy like most Clojure sequence functions. The advantage of laziness on sequences is that you are neither stack nor heap bound when operating on a stream. See alternative answers below that provide solutions to these concerns.

8 Comments

That's a very clever still simple solution. Thanks Timothy.
but it's not tail recursive! (partition-ghetto 10 (range 1000000)) => CompilerException java.lang.StackOverflowError, compiling:(form-init7979654044074214656.clj:875:28)
@Hooman - Thank you, glad it helped. @Leetwinski And it isn't lazy either! :) throwing in a lazy-seq would be one good improvement.
right, but while "not being lazy" is just ok for this toy exercise, "not being tail recursive" is just kind of a sabotage for the beginner clojure coder :) (remembering my first exercises)
I certainly don't wish to sabotage anyone. I'll delete this answer. Glad to see some discussion around better approaches.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.