Jason Basanese
Jason Basanese

Reputation: 710

Putting singles and lists into a list in clojure

Is there a more elegant way to have into work with single items and lists than the following (admittedly atrocious) function?

(defn into-1-or-more
  [this-list list-or-single]
  (into this-list (flatten (conj [] list-or-single))))

Which can handle either:

(into-1-or-more [1 2 3 4] 5)
;[1 2 3 4 5]

Or:

(into-1-or-more [1 2 3 4] [5 6 7 8])
;[1 2 3 4 5 6 7 8]

I am building a collection with reduce using into [] with results from functions in a list. However some of the functions return single items, and others return lists of items. Like:

(reduce #(into [] (% data)) [func-return-item func-return-list func-return-either])

Would the best solution be to just do the following instead?

(into [] (flatten (map #(% data) [func-return-item ...])

Upvotes: 0

Views: 148

Answers (2)

Alan Thompson
Alan Thompson

Reputation: 29958

Although it would be more ideal to know for sure what return type you are getting, here is a simple answer:

(flatten [ curr-list (mystery-fn) ] )

Examples:

(flatten [[1 2 3] 9 ] )
;=> (1 2 3 9)
(flatten [[[1] 2 3] [4 5] 6 ] )
;=> (1 2 3 4 5 6)

You could wrap it into a function if you want, but it hardly seems necessary.

Upvotes: 3

Michał Marczyk
Michał Marczyk

Reputation: 84331

This transducer flattens sequential inputs, but only by one "level":

(defn maybe-cat [rf]
  (let [catrf (cat rf)]
    (fn
      ([] (rf))
      ([result] (rf result))
      ([result input]
       (if (sequential? input)
         (catrf result input)
         (rf result input))))))

Example:

(into [] maybe-cat [[:foo] :bar [[:quux]]])
;= [:foo :bar [:quux]]

As this example demonstrates, this approach makes it possible to include sequential collections in the output (by wrapping them in an additional sequential layer – [[:quux]] produces [:quux] in the output).

Upvotes: 2

Related Questions