I'm currently working my way through a project using F#. I'm quite new to functional programming, and while I'm familiar with the idea of list items being immutable, I'm still having a bit of an issue:
I have a list of strings of the format
["(states, (1,2,3,4,5))"; "(alpha, (1,2))"; "(final, (1))"]
What I would like to do is turn each list element into its own list without the initial comma separated string. The output should look something like this:
["1"; "2"; "3"; "4"; "5"]
["1"; "2"]
["1"]
I've found myriad ways to concatenate list elements and my best guesses thus far (unfolding, or something of the sort) have been fruitless. Any help or a point in the right direction would be much appreciated. Thanks!
Operators for Working with Lists You can attach elements to a list by using the :: (cons) operator. If list1 is [2; 3; 4] , the following code creates list2 as [100; 2; 3; 4] . You can concatenate lists that have compatible types by using the @ operator, as in the following code.
F# Lists Creating lists A way to create a list is to place elements in two square brackets, separated by semicolons. The elements must have the same type. It is also possible to define lists of functions, of elements of a type defined previously, of objects of a class, etc.
In any list the first element is assigned index value 0 and the last element can be considered as a value -1.
Just for the fun of it, here's an outline of how to parse the strings using FParsec, a parser combinator library.
First, you import some modules:
open FParsec.Primitives
open FParsec.CharParsers
Then, you can define a parser that will match all strings enclosed by parentheses:
let betweenParentheses p s = between (pstring "(") (pstring ")") p s
This will match any string enclosed in parentheses, such as "(42)"
, "(foo)"
, "(1,2,3,4,5)"
, etc., depending on the specific parser p
passed as the first argument.
In order to parse numbers like "(1,2,3,4,5)"
or "(1,2)"
, you can combine betweenParentheses
with FParsec's built-in sepBy
and pint32
:
let pnumbers s = betweenParentheses (sepBy pint32 (pstring ",")) s
pint32
is a parser of integers, and sepBy
is a parser that reads a list of values, separated by a string - in this case ","
.
In order to parse an entire 'group' of values, such as "(states, (1,2,3,4,5))"
or "(alpha, (1,2))"
, you can again use betweenParentheses
and pnumbers
:
let pgroup s =
betweenParentheses
(manyTill anyChar (pstring ",") >>. spaces >>. pnumbers) s
The manyTill
combination parses any char
value until it encounters ,
. Next, the pgroup
parser expects any number of spaces, and then the format defined by pnumbers
.
Finally, you can define a function that runs the pgroup
parser on a string:
// string -> int32 list option
let parseGroup s =
match run pgroup s with
| Success (result, _, _) -> Some result
| Failure _ -> None
Since this function returns an option, you can use List.choose
to map the strings that can be parsed:
> ["(states, (1,2,3,4,5))"; "(alpha, (1,2))"; "(final, (1))"]
|> List.choose parseGroup;;
val it : int32 list list = [[1; 2; 3; 4; 5]; [1; 2]; [1]]
Using FParsec is most likely overkill, unless you have some more flexible formatting rules than what can easily be addressed with .NET's standard string
API.
You can also just use Char.IsDigit (at least based on your sample data) like so:
open System
// Signature is string -> string list
let getDigits (input : string) =
input.ToCharArray()
|> Array.filter Char.IsDigit
|> Array.map (fun c -> c.ToString())
|> List.ofArray
// signature is string list -> string list list
let convertToDigits input =
input
|> List.map getDigits
And testing it out in F# interactive:
> let sampleData = ["(states, (1,2,3,4,5))"; "(alpha, (1,2))"; "(final, (1))"];;
val sampleData : string list =
["(states, (1,2,3,4,5))"; "(alpha, (1,2))"; "(final, (1))"]
> let test = convertToDigits sampleData;;
val test : string list list = [["1"; "2"; "3"; "4"; "5"]; ["1"; "2"]; ["1"]]
NOTE: If you have more than 1 digit numbers, this will split them into individual elements in the list. If you don't want that you'll have to use regex or string.split or something else.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With