Fastest way to generate comma-separated list

625 views
Skip to first unread message

andrei

unread,
Oct 27, 2010, 8:18:08 PM10/27/10
to Clojure
Hi all,

I work with a database and need a function, that will convert Clojure
sequence to a string with a comma-separated elements. E.g.,

(comma-separated (list 1 2 3 4 5)) ==> "1, 2, 3, 4, 5"

It must work with any data type - ints, strings, other lists, etc.
E.g. for a list of strings it must generate

(comma-separated (list "1" "2" "3" "4" "5")) ==> "\"1\", \"2\",
\"3\", \"4\", \"5\""

I tried `cl-format` function from clojure.contrib.pprint package:

(cl-format nil "~{~S~^, ~}" lst)

It works fine, but is too slow. Next, I tried such function:

(defn comma-separated [s]
(if (= (type (first s)) String)
(chop (chop (chop (str "\" (apply str (interleave s
(repeatedly (fn [] "\", \"")))))))
(chop (chop (apply str (interleave s (repeatedly (fn [] ",
")))))))))

This one works much faster (~20 times), but it is ugly and still
doesn't cover all cases.

So, what is the fastest way to generate such list?

Christopher Petrilli

unread,
Oct 27, 2010, 8:24:54 PM10/27/10
to clo...@googlegroups.com
I didn't do any timing, but, I would say the idiomatic way:

(apply str (interpose ", " some-vector))

Chris

> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
>

--
| Chris Petrilli
| petr...@amber.org

andrei

unread,
Oct 27, 2010, 10:22:01 PM10/27/10
to Clojure

I was seeking `interpose` function, thanks. But it still doesn't work
for strings - they are not wrapped by "\"\. E.g.

(apply str (interpose ", " (list 1 2 3 4 5))) ==> "1, 2, 3, 4, 5"

and

(apply str (interpose ", " (list "1" "2" "3" "4" "5"))) ==> "1, 2, 3,
4, 5"

The problem is that applying `str` to strings just concatenates them
and doesn't include inverted commas. It's the same issue that applies
to `print` and `pr` functions - first just prints, and the second
prints in the form that can be read by reader. Is there an equivalent
of `pr` that returns string "as is"?

Of course, I can make such trick:

(defn pr-to-str [o]
(let [sw (StringWriter.)]
(binding [*out* sw]
(pr o))
(str sw)))


But aren't there such built-in function?

Stuart Campbell

unread,
Oct 27, 2010, 10:39:47 PM10/27/10
to clo...@googlegroups.com

Are you looking for pr-str?

user> (pr-str "foo")
"\"foo\""

Regards,
Stuart

Avram

unread,
Oct 28, 2010, 1:51:25 AM10/28/10
to Clojure

Does this help?

user> (use 'clojure.string)
nil
user> (join "," (range 10))
"0,1,2,3,4,5,6,7,8,9"

-Avram

andrei

unread,
Oct 28, 2010, 8:02:57 AM10/28/10
to Clojure


> Does this help?
>
> user> (use 'clojure.string)
> nil
> user> (join "," (range 10))
> "0,1,2,3,4,5,6,7,8,9"

It still doesn't work for the list of strings. But thanks for
reminding about it.

andrei

unread,
Oct 28, 2010, 8:04:32 AM10/28/10
to Clojure

> Are you looking for pr-str?
>
> user> (pr-str "foo")
> "\"foo\""

Yeah, that's exactly what I tried to implement with my `pr-to-str`,
thank you.
Message has been deleted

Ryan

unread,
Apr 2, 2013, 5:02:46 PM4/2/13
to clo...@googlegroups.com
andrei, can you please share the solution you came up after all?

Max Penet

unread,
Apr 2, 2013, 6:49:59 PM4/2/13
to clo...@googlegroups.com
Using a protocol fn to do the encoding of the values according to the rules you set per type then using clj.string/join should be quite fast and not so horrible. 

Jim - FooBar();

unread,
Apr 2, 2013, 7:33:22 PM4/2/13
to clo...@googlegroups.com
I'm sorry, I've not followed this discussion - what is wrong with

user=>(apply str (interpose \, (list 1 2 3 4 5)))
"1,2,3,4,5"

the problem is strings where you want to preserve each string...you can special case that and avoid the (apply str...) bit..
user=> (interpose \, (list "jim" "jon" "chris"))
("jim" \, "jon" \, "chris")...

once you have that pr-str is your friend...

=>(apply pr-str (interpose \, (list "jim" "jon" "chris")))
"\"jim\" \\, \"he\" \\, \"dan\"" 

Is this not exactly what you want and fast enough?

Jim
--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Ryan

unread,
Apr 2, 2013, 7:53:56 PM4/2/13
to clo...@googlegroups.com
Not sure if the OP will see this thread because I was the one that dig it up since I had a similar problem :)

user=> (apply pr-str (interpose \, (list "jim" "jon" "chris")))
"\"jim\" \\, \"jon\" \\, \"chris\""

I am not sure if that's correct. I think that the final string should look like this:

"\"jim\",\"jon\",\"chris\""

Ryan 

Max Penet

unread,
Apr 2, 2013, 7:56:57 PM4/2/13
to clo...@googlegroups.com
(comma-separated (list "1" "2" "3" "4" "5"))  ==>  "\"1\", \"2\", 
\"3\", \"4\", \"5
> It must work with any data type - ints, strings, other lists, etc. 

The OP needs different encoding rules per type (some of which are unspecified,  strings must be quoted, "etc."), and this could possibly be recursive (list of list of whatever and so on). 

Thomas Heller

unread,
Apr 3, 2013, 7:47:45 AM4/3/13
to clo...@googlegroups.com
My Question would be: why are you trying to do this? You mentioned you are working with a database, I assume that means SQL (as almost all NoSQL Databases support some kind of JSON which doesnt require your "workarround"). Most SQL Database support array types natively, while support might be a little itchy (at least in JDBC terms) it still beats a comma seperated list.

In all other cases just use clojure.core/pr-str and the new clojure.edn/read-string when reading it back.

Just my 2 cents,
/thomas


On Thursday, October 28, 2010 2:18:08 AM UTC+2, andrei wrote:

Ryan

unread,
Apr 3, 2013, 8:01:33 AM4/3/13
to clo...@googlegroups.com
Most SQL Database support array types natively

If you are using MySQL unfortunately there isn't and the OP (including myself) probably needs this because his RDBMS does not support the array type. 

Max Penet

unread,
Apr 3, 2013, 8:23:38 AM4/3/13
to clo...@googlegroups.com
I am curious, what data store are you interacting with? 
Reply all
Reply to author
Forward
0 new messages