How do I concatenate a list of strings in F#? - f#

I'm trying this at the moment, but I haven't quite got the method signature worked out... anyone? messages is a field of seq[string]
let messageString = List.reduce(messages, fun (m1, m2) -> m1 + m2 + Environment.NewLine)

> String.concat " " ["Juliet"; "is"; "awesome!"];;
val it : string = "Juliet is awesome!"

Not exactly what you're looking for, but
let strings = [| "one"; "two"; "three" |]
let r = System.String.Concat(strings)
printfn "%s" r
You can do
let strings = [ "one"; "two"; "three" ]
let r = strings |> List.fold (+) ""
printfn "%s" r
or
let strings = [ "one"; "two"; "three" ]
let r = strings |> List.fold (fun r s -> r + s + "\n") ""
printfn "%s" r

I'd use String.concat unless you need to do fancier formatting and then I'd use StringBuilder.
(StringBuilder(), [ "one"; "two"; "three" ])
||> Seq.fold (fun sb str -> sb.AppendFormat("{0}\n", str))

just one more comment,
when you are doing with string, you'd better use standard string functions.
The following code is for EulerProject problem 40.
let problem40 =
let str = {1..1000000} |> Seq.map string |> String.concat ""
let l = [str.[0];str.[9];str.[99];str.[999];str.[9999];str.[99999];str.[999999];]
l |> List.map (fun x-> (int x) - (int '0')) |> List.fold (*) 1
if the second line of above program uses fold instead of concat, it would be extremely slow because each iteration of fold creates a new long string.

System.String.Join(Environment.NewLine, List.to_array messages)
or using your fold (note that it's much more inefficient)
List.reduce (fun a b -> a ^ Environment.NewLine ^ b) messages

Related

Print list of document in reverse line by line

So I am working on this assignment where I have to reverse the document but it does not work as intended. If I run my code on a file like this
hello
world
I will get
dlrow
olleh
But what I really need is the following:
world
hello
So I need to reverse it line by line but not for every letter. I dont know how to tackle this problem so I need someone who can push me in the right direction. I think that I need to do something with my "q"
My Code is:
let readFile (filename : string) : string option =
try
let reader = System.IO.File.OpenText filename
Some (reader.ReadToEnd ())
with _ -> None
let tac (filenames : string list) : string option =
try
let q = List.map readFile filenames |> List.choose id |> String.concat ", " |> Seq.toList |> List.rev
(Some (System.String.Concat(Array.ofList (q))))
with _ -> None
As Daniel said, ...divide and conquer
Break it into smaller steps and solve one at a time
When you know what it takes to solve it,
you can then choose to improve it, 'refactor' it
to optimize
or add error handling
or specialize/rewrite a function
...etc
open System
open System.IO
// V1
File.ReadLines "./my.txt"
|> Seq.toList
|> List.rev
|> List.map (fun x -> sprintf "%s%s" x Environment.NewLine)
|> List.fold (+) ""
|> printf "%A\n"
... how do you reverse it without a for loop ?
open System
open System.IO
// v2
let rec reverse =
function
| [] -> []
| h::t -> (reverse t)#[h]
let join = List.fold (+) ""
let newLine x = sprintf "%s%s" x Environment.NewLine
// look , I'm a 'compositor' ! :) ♪
let chain = reverse >> List.map newLine >> join
File.ReadLines "./my.txt"
|> Seq.toList
|> chain
|> printf "%A\n"
... what if it doesn't exists ?
// V3
open System
open System.IO
let rec reverse =
function
| [] -> []
| h::t -> (reverse t)#[h]
let join = List.fold (+) ""
let newLine x = sprintf "%s%s" x Environment.NewLine
// 👣
let chain = reverse >> List.map newLine >> join
// NEW
let readLines path =
if File.Exists path then
// 🐛: What if its Binary or something line that ?
File.ReadLines path |> Seq.toList
else
[]
readLines "./my.txt"
|> chain
|> printf "%A\n"
[Edit]
Optional string version
// v4
open System
open System.IO
// New
let inline maybe test f x =
if test x then x |> f |> Some else None
// New
let inline ifSome f = maybe Option.isSome f
// New
let inline ifNone f = maybe Option.isNone f
// New
let ifExists = maybe File.Exists
let rec reverse =
function
| [] -> []
| h :: t -> (reverse t) # [ h ]
let join = List.fold (+) ""
let newLine x = sprintf "%s%s" x Environment.NewLine
let chain =
reverse
>> List.map newLine
>> join
let readLines path =
(File.ReadLines path)
|> Seq.toList
// usage '$ fsi reverse.fsx "my.txt"'
fsi.CommandLineArgs
|> Seq.skip 1
|> Seq.head // expecting "my.txt"
|> ifExists readLines
|> Option.map chain
|> ifSome (fun x -> printf "%A\n" x)
|> ifNone (fun x -> printf "None! \n")

F# - How to conveniently apply elements in a list to a curried function's parameters?

Supposed there is a list:
let lst = [1;2;3]
And a curried function:
let addAll a b c =
a + b + c
How can I input the parameters for the curried function coveniently using the elements in list lst?
One way of doing this is:
addAll (lst |> List.item 0) (lst |> List.item 1) (lst |> List.item 2)
But this doesn't scale very well! Also, it's boring.
It is hard to say from the limited example what your actual use case is. Lists are designed to contain a varying number of items and functions take constant number of items, so the two do not match well. It might make more sense to use a tuple rather than a list:
let tup = (1,2,3)
let addAll (a, b, c) =
a + b + c
addAll tup
Tuples contain fixed number of items, but they can be easily constructed and deconstructed and allow you to pass all parameters to your function at once.
You can also do what you asked about using reflection, but this may break in future versions of F# and it is almost never a good design for a simple case like this. It is also slow and as you can see from the number of downcasts and boxing, it is also not very safe:
let lst = [1;2;3]
let addAll a b c =
a + b + c
let addAllVal = addAll
let f = addAllVal.GetType().GetMethod("Invoke", [| typeof<int>; typeof<int>; typeof<int> |])
let res = f.Invoke(addAllVal, Array.map box (Array.ofList lst)) :?> int
Another option is to use pattern matching:
let lst = [1;2;3]
match lst with [ a ; b; c] -> addAll a b c |_-> 0
returns 6.
If lst does not have exactly 3 elements then it returns 0 but you can change it to handle other cases:
let callAddAll lst =
match lst with
| [ ] -> 0
| [ a ] -> addAll a 0 0
| [ a ; b ] -> addAll a b 0
| [ a ; b ; c ] -> addAll a b c
| a :: b :: c :: rest -> addAll a b c // ignore rest
[ ] |> callAddAll |> printfn "lst = %d" // = 0
[1 ] |> callAddAll |> printfn "lst = %d" // = 1
[1;2 ] |> callAddAll |> printfn "lst = %d" // = 3
[1;2;3 ] |> callAddAll |> printfn "lst = %d" // = 6
[1;2;3;4] |> callAddAll |> printfn "lst = %d" // = 6

F# suitable container for (string, float, float) triads?

I have the following problem and I hope somebody can help me.
Short description of the problem: i need to store a (string A, float B, float C) triad into a suitable container. The triad originates fomr a double "for" loop.
But the essential point is that I will need to slice this container when the loops are over to perform other operations.
An example that can be executed from the .fsx shell (using Deedle frames) follows. The triad is what is beeing printed on the screen.
open Deedle
let categorical_variable = [| "A"; "B"; "C"; "A"; "B"; "C"; |]
let vec_1 = [| 15.5; 14.3; 15.5; 14.3; 15.5; 14.3; |]
let vec_2 = [| 114.3; 17.5; 9.3; 88.7; 115.5; 12.3; |]
let dframe = frame ["cat" =?> Series.ofValues categorical_variable
"v1" =?> Series.ofValues vec_1
"v2" =?> Series.ofValues vec_2 ]
let distinct_categorical_variables = categorical_variable |> Array.toSeq |> Seq.distinct |> Seq.toArray
let mutable frame_slice : Frame<int, string> = Frame.ofRows []
let mutable frame_slice_vec_1 : float[] = Array.empty
let mutable frame_slice_vec_1_distinct : float[] = Array.empty
for cat_var in distinct_categorical_variables do
frame_slice <- (dframe |> Frame.filterRowValues (fun row -> row.GetAs "cat" = cat_var))
frame_slice_vec_1 <- (frame_slice?v1).Values |> Seq.toArray
frame_slice_vec_1_distinct <- (frame_slice_vec_1 |> Array.toSeq |> Seq.distinct |> Seq.toArray)
for vec_1_iter in frame_slice_vec_1_distinct do
printfn "%s, %f, %f \n" cat_var vec_1_iter (Array.average ((frame_slice?v2).Values |> Seq.toArray) ) |> ignore
So, is there any suitable object where to store this triad? I saw Array3d objects, but I don't think they are the right solution cause A, B and C of my triad have different types.
Many thanks in advance.
you probably want a sequence expression with tuples:
let mySequence =
seq { for cat_var in distinct_categorical_variables do
...
for vec_1_iter in ... do
yield cat_var, vec_1_iter, Array.average ... }
// then use it like
for cat_var, vec_1_iter, result in mySequence do
...

Find all strings which has sub-string of an item in another string list

I have the following code.
let s1 = [(12, "abcde12345"); (23, "bcdef2345"); (12, "xyzafg3838")]
let s2 = ["bcd"; "345"]
What's the best way to find all items in s1 which second item has sub-string of any one in s2?
(12, "abcde12345"); (23, "bcdef2345")
In my real code s1 is a Seq.
Seq.filter (fun (_, x) -> List.exists (x.Contains) s2) s1
I figured out one.
s1 |> Seq.filter (fun i -> List.exists (fun e -> (snd i).Contains(e)) s2)
Concat all of the items from the second set into a regular expression, then apply it on each item in the first set.
open System
open System.Text.RegularExpressions
let setA = [ "One"; "Two"; "Three" ]
let setB = [ "o"; "n" ];
let pattern = String.Join("|", setB);
let regex = new Regex(pattern);
let results = setA |> List.filter (fun str -> regex.Match(str).Success)
results |> List.iter (fun result -> Console.WriteLine(result))

F# List of random numbers concatenated

Can someone tell me why this works
let createRandomList = List.init 9 (fun _ -> randomNumberGenerator.Next(0,9))
let concatRandomList =
createRandomList
|> Seq.map string
|> String.concat ""
and this does not?
let createConcatRandomList = List.init 9 (fun _ -> randomNumberGenerator.Next(0,9))
|> Seq.map string
|> String.concat ""
I am getting an "Incomplete value or function definition" on the second code block
Thanks in advance
In the second example you need to indent the |> to the same level as List

Resources