4

I'm learning Clojure and actually I'm doing some exercises to practice but I'm stuck in a problem:

I need to make a sum-consecutives function which sums consecutive elements in a array, resulting in a new one, as example:

[1,4,4,4,0,4,3,3,1]  ; should return [1,12,0,4,6,1]

I made this function which should work just fine:

(defn sum-consecutives [a]
  (reduce #(into %1 (apply + %2)) [] (partition-by identity a)))

But it throws an error:

IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:542)

Can anyone help me see what is wrong with my func? I've already search this error in web but I find no helpful solutions.

Micah Elliott
  • 9,600
  • 5
  • 51
  • 54
guijob
  • 4,413
  • 3
  • 20
  • 39

2 Answers2

2

You'll likely want to use conj instead of into, as into is expecting its second argument to be a seq:

(defn sum-consecutives [a]
  (reduce 
    #(conj %1 (apply + %2))
    [] 
    (partition-by identity a)))

(sum-consecutives [1,4,4,4,0,4,3,3,1]) ;; [1 12 0 4 6 1]

Alternatively, if you really wanted to use into, you could wrap your call to apply + in a vector literal like so:

(defn sum-consecutives [a]
  (reduce 
    #(into %1 [(apply + %2)])
    [] 
    (partition-by identity a)))
pdoherty926
  • 9,895
  • 4
  • 37
  • 68
  • Your conj resolution worked fine showing exactly what I was missing. I'm going study deeper about these functions. thank you for your help – guijob Jul 18 '17 at 18:03
2

Your approach is sound in starting with partition-by. But let's walk through the steps to sum each subsequence that it produces.

(let [xs [1 4 4 4 0 4 3 3 1]]
  (partition-by identity xs))  ;=> ((1) (4 4 4) (0) (4) (3 3) (1))

To get a sum, you can use reduce (though a simple apply instead would also work here); e.g.:

(reduce + [4 4 4])  ;=> 12

Now put it all together to reduce each subsequence from above with map:

(let [xs [1 4 4 4 0 4 3 3 1]]
  (map #(reduce + %) (partition-by identity xs)))  ;=> (1 12 0 4 6 1)

A few notes...

I'm using xs to represent your vector (as suggested by the Clojure Style Guide).

The let is sometimes a convenient form for experimenting with some data building up to eventual functions.

Commas are not needed and are usually distracting, except occasionally with hash-maps.

So your final function based on all this could look something like:

(defn sum-consecutives [coll]
  (map #(reduce + %) (partition-by identity coll)))
Micah Elliott
  • 9,600
  • 5
  • 51
  • 54