Retrieving elements of a set as a concatenated string

I’m trying to pull out each element of in a Set of string elements i have and append it (concatenate it) to one single variable.
I’m not able to figure out how to use map or fold, since i want the resulting concatenated object to be returned.
Would be great if someone could suggest how i can get this done.

This is the code i have thus far -

module SS = Set.Make(String);;
... definition of create_set ... 
let set_obj = create_set list_of_words;;
let all_unique_words = ??

where create_set is a function which goes through list_of_words and based on some logic, returns a set of strings.
what i’d want is for all these strings to be concatenated into one string by a delimiter of my choice.

ideally, this would be the pseudo code

function foo (delimiter, set_obj):
   final_string = " "
   foreach element in set_obj:
       final_string = final_string + element + delimiter
    return final_string

The simplest solution is to use String.concat:

let final_string = String.concat ", " (SS.elements set_obj)

To skip the intermediate list, you could use

let final_string =
  let buf = Buffer.create 128 in
  let sep = ref "" in
  SS.iter (fun s -> Buffer.add_string buf !sep; sep := ", "; Buffer.add_string s) set_obj;
  Buffer.contents set_obj
2 Likes

@paurkedal
thanks, petter.
could you perhaps explain what is happening in these lines.

let sep = ref “” in
SS.iter (fun s → Buffer.add_string buf !sep; sep := ", "; Buffer.add_string s) set_obj;
Buffer.contents set_obj

i realize i could go through the syntax bit by bit and google it and understand what’s happening there.
but would be great if you could articulate the larger approach and what’re the key OCaml constructs you use to help convert those ideas to code.

thanks!

Set’s iter method calls a function for every element in the set and this gets added to the end of the buffer. In between each item you want a ", " which is what sep is doing. The first time, it’s the empty string, so nothing happens but in all the future calls it will have been updated to ", ". Personally, I dislike refs unless I’m forced kicking and screaming to do so, I’d use fold:

let final_string =
  let buf = Buffer.create 1024 in
  let _ = SS.fold (fun s sep -> Buffer.add_string sep; Buffer.add_string s; ", ") set_obj in
  Buffer.contents set_obj

@Sha_Kurukshetra I think the explanation from @dra27, should cover it. If the container in question has an iteri function (iterate with and index argument), then there is another alternative. So, here is another slightly more elaborate example of using Buffer with iteri:

let string_of_array string_of_elt array =
  let buf = Buffer.create 256 in
  let add_elt i x =
    if i > 0 then Buffer.add_string buf "; ";
    Buffer.add_string buf (string_of_elt x) in
  Buffer.add_string buf "[|";
  Array.iteri add_elt array;
  Buffer.add_string buf "|]";
  Buffer.contents buf
;;
string_of_array string_of_int [|8; 2; 100|];;

I took with me the idiom of overwriting a “sep” variable from C, and it’s still ugly. The fold variant is nicer. (I tend to pick iter for Buffer processing since it’s an imperative structure, but of course in OCaml it’s perfectly fine to pass an imperative function to fold.)