Categories
Tech

F# Friday – The concat Function

Collections

F#’s sequential collections all define the concat function: Array.concat, List.concat, and Seq.concat. The concat function takes a sequence of arrays, lists, or sequences and flattens them. (In fact, some languages call this operation “flatten.”) That is, it takes the elements of the nested collections, pulls them out, and puts them all together in order in a new sequential collection, according to the type of the nested collection.

To illustrate, let’s say that the (now defunct) Java Posse podcast members and the .NET Rocks podcast members want to get together (as they did once before) to do a combined podcast—a panel, if you will, or an omni-podcast:

let javaPosse = ["Dick"; "Tor"; "Carl"; "Chet"]
let dotNetRocks = ["Carl"; "Richard"]
let podcasts = seq [javaPosse; dotNetRocks]
// val podcasts : seq<string list> =
//   [
//     ["Dick"; "Tor"; "Carl"; "Chet"];
//     ["Carl"; "Richard"]
//   ]

So now you have a list of lists. To get your omni-podcast panel, you call List.concat on podcasts:

let panel = List.concat podcasts
// val panel : string list =
//   ["Dick"; "Tor"; "Carl"; "Chet"; "Carl"; "Richard"]

As you can see, concat flattens the nested lists into one long list and preserves the order of the elements as they were in the original nested lists.

Another illustration: File.ReadAllLines reads all the lines of a file into an array. If you should need an omnibus array of all of the lines in a collection of files, you could do this:

let files = [| "file1.txt", "file2.txt" |]
let allLines =
  files
  |> Array.map File.ReadAllLines  // nested arrays of lines
  |> Array.concat  // flattens nested arrays into one array
// val lines : string [] =
//   [|
//     "file1 line1"; "file1 line2";
//     "file2 line1"; "file2 line2"; "file2 line3";
//      ...
//   |]

Strings

The String module also defines a concat function. It takes a sequence of strings and joins them all together into one string. String.concat is a little different from the collection versions of the concat function in that it takes two parameters: the string sequence is the second parameter, but the first is a separator or delimiter string. (Some languages call this operation “join.”)

For example, if you have a list of names that you want to concatenate together, but separate with a comma and a space, this gets you where you want to go:

let beatles =
  ["John"; "Paul"; "George"; "Ringo"]
  |> String.concat ", "
// val beatles : string = "John, Paul, George, Ringo"

But if you want to make String.concat act just like the collection versions of concat, that is, just to jam the strings together with no delimiter, just use en empty string as your delimiter:

let atrocious =
  [
    "super"; "cali"; "fragi"; "listic";
    "expi"; "ali"; "docious"
  ]
  |> String.concat ""
// val atrocious : string =
//   "supercalifragilisticexpialidocious"

2 replies on “F# Friday – The concat Function”

Thank you, you solved my issue! String.concat was what I was after instead of List.concat. Yay, I can move forward again. :-)

Yeah, I want that to be String.join so badly! Not a great name.

Anyway, glad to help.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.