简体   繁体   中英

Grouping a seq by different sizes - Clojure

I have the following data:

(def letters [:a :b :c :d :e :f :g ])
(def group-sizes [2 3 2])

What would be an idiomatic way to group letters by size, such that I get:

[[:a :b] [:c :d :e] [:f :g]]

Thanks.

(->> group-sizes
     (reductions + 0)
     (partition 2 1)
     (map (partial apply subvec letters)))

This algorithm requires the input coll letters to be a vector and to have at least the required amount of (apply + group-sizes) elements. It returns a lazy seq (or a vector if you use mapv ) of vectors that share structure with the input vector.

Thanks to subvec they are created in O(1), constant time so the overall time complexity should be O(N) where N is (count group-sizes) , compared to Diegos algorithm where N would be the drastically higher (count letters) .

After I started writing my answer, I noticed, that Leon Grapenthin 's solution is almost identical to mine.

Here is my version of it:

(let [end   (reductions + group-sizes)
      start (cons 0 end)]
  (map (partial subvec letters) start end))

The only difference from Leon Grapenthin 's solution is that I'm using let and cons instead of partition and apply .

Note, that both solutions consume group-sizes lazily, thus producing a lazy sequence as an output.

Not necessarily the best way (eg you may want to check that the sum of the group sizes is the same as the size of letters to avoid an NPE) but it was my first thought:

(defn sp [[f & r] l]
  (when (seq l)
    (cons (take f l)
          (sp r (drop f l)))))

You could also do it with an accumulator and recur if you have a long list and don't want to blow up the stack.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM