choochy
choochy

Reputation: 29

Convert each string in a list into a list of strings

I have two functions, one is

let make_row delim str = List.map String.trim (Str.split (Str.regexp delim) str)

and the other is

let rec table_of_stringlist delim rlist = match rlist with
| h::[]-> make_row delim h
| h::t -> table_of_stringlist delim (make_row delim h)::t)

but the second one is giving me trouble. I am trying to make it so essentially table_of_stringlist d [r1;r2;...;rN] should evaluate to [(make_row d r1); (make_row d r2); ...; (make_row d rN)]. The value d is a delimiter so for example table_of_stringlist "|" ["a|b|c"; "d|e"] should evaluate to [["a";"b";"c"]; ["d";"e"]]. I am confused on how to write my match cases in the second function. Any help would be great.

Upvotes: 0

Views: 166

Answers (2)

Chris
Chris

Reputation: 36496

I'm going to rearrange your first function a little bit for readability.

let make_row delim str = 
  let delim = Str.regexp delim in
  str 
  |> Str.split delim
  |> List.map String.trim 

Now, let's give your second function some attention. Aside from some syntactic changes, you had an extraneous paren at the end. If we remove that, we see:

let rec table_of_stringlist delim rlist = 
  match rlist with
  | [h] -> make_row delim h
  | h::t -> table_of_stringlist delim (make_row delim h) :: t

Problems:

This doesn't handle the case where rlist is empty.

The function is not recursively being called on the tail of the list, but rather on the results of making a "row" out of the first string. This prompts a type error.

utop # let rec table_of_stringlist delim rlist =
  match rlist with
  | [h] -> make_row delim h
  | h::t -> table_of_stringlist delim (make_row delim h) :: t;;
Error: This expression has type string list
       but an expression was expected of type string

Because t has type string list anything prepended onto it with :: must be a string, but make_row returns a string list.

We can address the first concern by having your function return an empty list when rlist is empty. The second concern we address by applying make_row to the first element, and recursively calling table_of_stringlist on the tail, consing the two together with ::.

let rec table_of_stringlist delim rlist =
  match rlist with
  | [] -> []
  | h::t -> (make_row delim h) :: table_of_stringlist delim t
utop # table_of_stringlist "|" ["a|b|c"; "d|e"];;
- : string list list = [["a"; "b"; "c"]; ["d"; "e"]]

Of course, this is really just List.map.

let table_of_stringlist delim rlist = 
  List.map (fun x -> make_row delim x) rlist

Or more tersely:

let table_of_stringlist delim = List.map (make_row delim)

Upvotes: 0

Shawn
Shawn

Reputation: 165

You'll want to pass the new list (the table) along your recursive function as you build it, returning that new list once you reach the end of rlist

let rec table_of_stringlist delim rlist table = match rlist with
| [] -> table
| h::t->
    let new_row = make_row delim h in
    table_of_stringlist delim t (table @ [new_row])

When you call it the first time, pass in an empty list as the table.

Note: I haven't actually tested the snipped above so it may not be syntactically correct, but it should be close to what you need.

Upvotes: 1

Related Questions