matekus
matekus

Reputation: 788

F# - Combine Multiple Column String Lists Into Array

I have a number of column string lists (11), which I would like to combine into a single array:

[List1]
Alpha
Bravo
Charlie

[List2]
3
5
7

[List3]
11
13
17

for export to csv file:

[Array]
Alpha     3   11
Bravo     5   13
Charlie   7   17

Is this possible and, if so, how?

Upvotes: 0

Views: 302

Answers (1)

s952163
s952163

Reputation: 6324

Yes, basically you want to transpose. You can write your own function or use something from a Matrix library or Deedle. This is easy to do with a for comprehension as well. You will need to first map all elements of the list to be strings. Finally use String.concat to join the elements of the array:

let list1 = ["Alpha";"Bravo";"Charlie"]
let list2 = ["3";"5";"7"]
let list3 = ["11";"13";"17"]

let lists = [list1;list2;list3] // create a list of lists

[|for i in [0 .. (lists.Length - 1)] do
    for j in [0 .. (lists.[i].Length - 1)] do 
    yield lists.[j].[i] // swap rows and columns
|] 
|> Array.splitInto (lists.Length) // 
|> Array.map (fun x -> String.concat "," x) // join the array elements with a comma for CSV output. 

Output:

// val it : string [] = [|"Alpha,3,11"; "Bravo,5,13"; "Charlie,7,17"|]

After this you can just use File.WriteAllLines or a similar method to dump this into a file.

Edit: Let's add list4:

let list4 = ["19";"23";"29"]
let lists = [list1;list2;list3;list4]

If you think about it for a bit, you will realize that you want the first element of each list, basically its head:

lists
|> List.map List.head
//val it : string list = ["Alpha"; "3"; "11"; "19"]

Now if you could jus thread this function through the remaining part of the list (once you take the head, you have the tail left), so for the next row:

lists 
|> List.map List.tail
|> List.map List.head
//val it : string list = ["Bravo"; "5"; "13"; "23"]

Now if you could just repeat this until you ran out of lists...you actually can, with recursion:

let rec transpose xs =
    match xs with
    []::xs -> []
    | xs -> List.map List.head xs :: transpose (List.map List.tail xs)

transpose lists
|> Array.ofList
|> Array.map (fun x -> String.concat "," x)

//val it : string list list =
//[["Alpha"; "3"; "11"; "19"]; ["Bravo"; "5"; "13"; "23"];
// ["Charlie"; "7"; "17"; "29"]]

//val it : string [] =  [|"Alpha,3,11,19"; "Bravo,5,13,23"; "Charlie,7,17,29"|]

Upvotes: 1

Related Questions