0

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?

3
  • 2
    Which particular part of this problem are you stuck on? Commented Oct 16, 2017 at 10:35
  • John, the first part - combining column lists into an array? Commented Oct 16, 2017 at 10:40
  • 1
    Hint: look for a transpose function. It will help if you write the signatures of the input and output you expect. Commented Oct 16, 2017 at 12:48

1 Answer 1

1

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"|]
Sign up to request clarification or add additional context in comments.

2 Comments

It appears to fail if I add another list - let list4 = ["19";"23";"29"]! Am I missing something?
@matekus yes, you would get an index out of bounds error. That's why it's not a good idea to use positional indexing. It's helpful though to indicate how it appears to fail. I'll add a version that uses recursion, if you could rewrite it with a fold that would be great. :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.