Convert string [,] into string representation - multidimensional-array

Let say I have this two-dimensional array:
let a = Array2D.create 2 2 "*"
What is an idiomatic way to turn that into the following string?
**\n
**\n
My thought would be that I need to iterate over the rows and then map string.concat over the items in each row. However I can't seem to figure out how to iterate just the rows.

I think you'll have to iterate over the rows by hand (Array2D does not have any handy function for this),
but you can get a row using splicing syntax. To get the row at index row, you can write array.[row, *]:
let a = Array2D.create 3 2 "*"
[ for row in 0 .. a.GetLength(0)-1 ->
String.concat "" a.[row,*] ]
|> String.concat "\n"
This creates a list of rows (each turned into a string using the first String.concat) and then concatenates the rows using the second String.concat.

Alternatively, you may use StringBuilder and involve Array2D.iteri function:
let data' = [|[|"a"; "b"; "c"|]; [|"d"; "e"; "f"|]|]
let data = Array2D.init 2 3 (fun i j -> data'.[i].[j])
open System.Text
let concatenateArray2D (data:string[,]) =
let sb = new StringBuilder()
data
|> Array2D.iteri (fun row col value ->
(if col=0 && row<>0 then sb.Append "\n" else sb)
.Append value |> ignore
)
sb.ToString()
data |> concatenateArray2D |> printfn "%s"
This prints:
abc
def

Related

How to read pair by pair from a file in SML?

I want to read N pairs from a file and store them as a tuples in a list.For example if i have these 3 pairs : 1-2 , 7-3, 2-9 i want my list to look like this -> [(1,2),(7,3),(2-9)]
I tried something like this:
fun ex filename =
let
fun readInt input = Option.valOf (TextIO.scanStream (Int.scan StringCvt.DEC) input)
val instream = TextIO.openIn filename
val T = readInt instream (*number of pairs*)
val _ = TextIO.inputLine instream
fun read_ints2 (x,acc) =
if x = 0 then acc
else read_ints2(x-1,(readInt instream,readInt instream)::acc)
in
...
end
When i run it i get an exeption error :/ What's wrong??
I came up with this solution. I reads a single line from the given file. In processing the text it strips away anything not a digit creating a single flat list of chars. Then it splits the flat list of chars into a list of pairs and in the process converts the chars to ints. I'm sure it could be improved.
fun readIntPairs file =
let val is = TextIO.openIn file
in
case (TextIO.inputLine is)
of NONE => ""
| SOME line => line
end
fun parseIntPairs data =
let val cs = (List.filter Char.isDigit) (explode data)
fun toInt c =
case Int.fromString (str c)
of NONE => 0
| SOME i => i
fun part [] = []
| part [x] = []
| part (x::y::zs) = (toInt x,toInt y)::part(zs)
in
part cs
end
parseIntPairs (readIntPairs "pairs.txt");

How do I print out year with average number recursively in F#?

Okay, so I have approached this headache for a couple days by trying to figure out how to print out year with average number from per line in my text file. I asked this similar question a couple days ago so basically I'm asking the same question, How do I print out lines recursively from a text file along with the average value of total elements from per line?
this goes on. However, I have created several functions. Now, here is my new question. Why does my program's output looks like this in the picture below? I have commented out a couple questions in my codes. I have been expecting to have output like
2010: 3.5788888
2009: 4.697858
This list goes on recursively.
here is my updated codes:
let ReadFile filename =
[ for line in System.IO.File.ReadLines(filename) -> line ]
let ParseLine (line:string) =
let strings = line.Split('\t')
let strlist = Array.toList(strings)
let year = System.Int32.Parse(strlist.Head)
let values = List.map System.Double.Parse strlist.Tail
(year, values)
let rec print (year, values) =
if values = [] then
()
else
printfn "%A: %A" year values.Head
print (year, values.Tail)
let avg (values:double list) = //this function can compute the average, but it wont work when I do in main, print(firstYear, avg (firstYear1))
let rec sum values accum =
match values with
| [] -> accum
| head :: tail -> sum tail (accum + head/12.0)
sum values 0.0
let rec sum (year, values:double list) =
if values = [] then
0.0
else
values.Head + sum (year, values.Tail)
[<EntryPoint>]
let main argv =
// read entire file as list of strings:
let file = ReadFile "rainfall-midway.txt"
printfn "** Rainfall Analysis Program **"
printfn ""
// let's parse first line into tuple (year, list of rainfall values),
// and then print for debugging:
let (year, values) = ParseLine file.Head
let firstYear = file.Head
let firstYear1 = file.Tail
//let data = List.map ParseLine file //I know map would be the key, but how does this work with year and its elements?
//let firstYear = data.Head
//let firstYear = data.Head
//print firstYear
print (firstYear, firstYear1)
//let S = sum firstYear
//printfn "%A" S
//let A = S / 12.0
//printfn "%A" A
// done:
printfn ""
printfn ""
0 // return 0 => success
The code you have is actually quite close to giving you the data you expect. There are a couple changes you could make to simplify things.
First to answer your question
Why does my program's output looks like this in the picture below?
This is because you are printing out the year and all of the parsed values (this doesn't match the code which just prints out the file). An easy way to resolve this is to have the ParseLine function calculate the average. You will need to move the avg prior to the ParseLine function but that should not be a problem.
let avg (values:double list) =
let rec sum values accum =
match values with
| [] -> accum
| head :: tail -> sum tail (accum + head/12.0)
sum values 0.0
let ReadFile filename =
[ for line in System.IO.File.ReadLines(filename) -> line ]
let ParseLine (line:string) =
let strings = line.Split('\t')
let strlist = Array.toList(strings)
let year = System.Int32.Parse(strlist.Head)
let values = List.map System.Double.Parse strlist.Tail
(year, avg values) // calculate avg here
Once that is done, you can use a map to run ParseLine on all lines from the file.
let result = file |> List.map ParseLine
Then to print out the results you need only iterate through the result list.
result |> List.iter(fun (year, avgRainfall) -> printfn "%i: %f" year avgRainfall)
That said we could just remove the sum and avg functions altogether and use fold instead in our ParseLine function.
let ParseLine (line:string) =
let strings = line.Split('\t')
let strlist = Array.toList(strings)
let year = System.Int32.Parse(strlist.Head)
year, (strlist.Tail |> List.fold(fun state el -> (System.Double.Parse el + state)) 0.0) / float strlist.Tail.Length
If you don't want to change the ParseLine function then you can do the following:
let result = file |> List.map(fun el ->
let (year, values) = ParseLine el
(year, avg values))

F# recursion behavior

I recently started learning F# and because I am quite new to most of the functional concepts I tend to want to write small examples for myself and check my premises with the results of the test.
Now I can't seem to be able to understand the result of the following code and why it behaves as such. The use case: I roll four six sides dice and only return their total when their sum is greater than 20.
This is my code:
let rnd = System.Random()
let d6 () = rnd.Next(1, 7)
let rec foo () =
// create a list of 4 d6 throws and print out the list
let numbers = seq { for i in 1 .. 4 -> d6() }
numbers |> Seq.iter( fun n -> printf "%i " n )
printfn "\n"
// sum the list and return the sum only when the sum is greater than 20
let total = numbers |> Seq.sum
match total with
| n when n < 21 -> foo ()
| _ -> total
Now when you run this you will find that this will eventually return a number greater than 20.
When you look at the output you will find that it did not print out the last list of numbers and I can't figure out why.
The sequences are lazily evaluated and are not cached. What happens here is that you have a sequence with a side effect that's evaluated multiple times.
First evaluation yields first sequence of random numbers:
numbers |> Seq.iter( fun n -> printf "%i " n )
The second call runs the evaluation again, producing completely different sequence:
let total = numbers |> Seq.sum
What you need to do if you want to keep the first evaluation around to run through it multiple times is either materialize the sequence or cache it:
// create a list directly
let numbers = [ for i in 1 .. 4 -> d6() ]
// or create a list from sequence
let numbers = seq { for i in 1 .. 4 -> d6() } |> List.ofSeq
// or cache the sequence
let numbers = seq { for i in 1 .. 4 -> d6() } |> Seq.cache

F#- AsyncSeq - how to return values in a list

Attempting to find anagrams in a list of words using F Sharps Async Sequences (I am aware there are better algorithms for anagram finding but trying to understand Async Sequneces)
From the 'runTest' below how can I
1. async read the collecion returned and output to screen
2. block until all results return & display final count/collection
open System
open System.ServiceModel
open System.Collections.Generic
open Microsoft.FSharp.Linq
open FSharp.Control
[<Literal>]
let testWord = "table"
let testWords = new List<string>()
testWords.Add("bleat")
testWords.Add("blate")
testWords.Add("junk")
let hasWord (word:string) =
let mutable res = true
let a = testWord.ToCharArray() |> Set.ofArray
let b = word.ToCharArray() |> Set.ofArray
let difference = Set.intersect a b
match difference.Count with
| 0 -> false
| _ -> true
let test2 (words:List<string>, (word:string)) : AsyncSeq<string> =
asyncSeq {
let res =
(words)
|> Seq.filter(fun x-> (hasWord(x)) )
|> AsyncSeq.ofSeq
yield! res
}
let runTest = test2(testWords,testWord)
|> //pull stuff from stream
|> // output to screen
|> ignore
()
So as you have the test2 function returning an asyncSeq. Your questions:
1. async read the collecion returned and output to screen
If you want to have some side-effecting code (such as outputting to the screen) you can use AsyncSeq.iter to apply a function to each item as it becomes available. Iter returns an Async<unit> so you can then "kick it off" using an appropriate Async method (blocking/non-blocking).
For example:
let processItem i =
// Do whatever side effecting code you want to do with an item
printfn "Item is '%s'" i
let runTestQ1 =
test2 (testWords, testWord)
|> AsyncSeq.iter processItem
|> Async.RunSynchronously
2. block until all results return & display final count/collection
If you want all the results collected so that you can work on them together, then you can convert the AsyncSeq into a normal Seq using AsyncSeq.toBlockingSeq and then convert it to a list to force the Seq to evaluate.
For example:
let runTestQ2 =
let allResults =
test2 (testWords, testWord)
|> AsyncSeq.toBlockingSeq
|> Seq.toList
// Do whatever you would like with your list of results
printfn "Final list is '%A' with a count of %i" allResults (allResults.Length)

functional programming with less recursion?

I am currently doing reasonably well in functional programming using F#. I tend, however, to do a lot of programming using recursion, when it seems that there are better idioms in the F#/functional programming community. So in the spirit of learning, is there a better/more idiomatic way of writing the function below without recursion?
let rec convert line =
if line.[0..1] = " " then
match convert line.[2..] with
| (i, subline) -> (i+1, subline)
else
(0, line)
with results such as:
> convert "asdf";;
val it : int * string = (0, "asdf")
> convert " asdf";;
val it : int * string = (1, "asdf")
> convert " asdf";;
val it : int * string = (3, "asdf")
Recursion is the basic mechanism for writing loops in functional languages, so if you need to iterate over characters (as you do in your sample), then recursion is what you need.
If you want to improve your code, then you should probably avoid using line.[2..] because that is going to be inefficient (strings are not designed for this kind of processing). It is better to convert the string to a list and then process it:
let convert (line:string) =
let rec loop acc line =
match line with
| ' '::' '::rest -> loop (acc + 1) rest
| _ -> (acc, line)
loop 0 (List.ofSeq line)
You can use various functions from the standard library to implement this in a more shorter way, but they are usually recursive too (you just do not see the recursion!), so I think using functions like Seq.unfold and Seq.fold is still recursive (and it looks way more complex than your code).
A more concise approach using standard libraries is to use the TrimLeft method (see comments), or using standard F# library functions, do something like this:
let convert (line:string) =
// Count the number of spaces at the beginning
let spaces = line |> Seq.takeWhile (fun c -> c = ' ') |> Seq.length
// Divide by two - we want to count & skip two-spaces only
let count = spaces / 2
// Get substring starting after all removed two-spaces
count, line.[(count * 2) ..]
EDIT Regarding the performance of string vs. list processing, the problem is that slicing allocates a new string (because that is how strings are represented on the .NET platform), while slicing a list just changes a reference. Here is a simple test:
let rec countList n s =
match s with
| x::xs -> countList (n + 1) xs
| _ -> n
let rec countString n (s:string) =
if s.Length = 0 then n
else countString (n + 1) (s.[1 ..])
let l = [ for i in 1 .. 10000 -> 'x' ]
let s = new System.String('x', 10000)
#time
for i in 0 .. 100 do countList 0 l |> ignore // 0.002 sec (on my machine)
for i in 0 .. 100 do countString 0 s |> ignore // 5.720 sec (on my machine)
Because you traverse the string in a non-uniform way, a recursive solution is much more suitable in this example. I would rewrite your tail-recursive solution for readability as follows:
let convert (line: string) =
let rec loop i line =
match line.[0..1] with
| " " -> loop (i+1) line.[2..]
| _ -> i, line
loop 0 line
Since you asked, here is a (bizarre) non-recursive solution :).
let convert (line: string) =
(0, line) |> Seq.unfold (fun (i, line) ->
let subline = line.[2..]
match line.[0..1] with
| " " -> Some((i+1, subline), (i+1, subline))
| _ -> None)
|> Seq.fold (fun _ x -> x) (0, line)
Using tail recursion, it can be written as
let rec convert_ acc line =
if line.[0..1] <> " " then
(acc, line)
else
convert_ (acc + 1) line.[2..]
let convert = convert_ 0
still looking for a non-recursive answer, though.
Here's a faster way to write your function -- it checks the characters explicitly instead of using string slicing (which, as Tomas said, is slow); it's also tail-recursive. Finally, it uses a StringBuilder to create the "filtered" string, which will provide better performance once your input string reaches a decent length (though it'd be a bit slower for very small strings due to the overhead of creating the StringBuilder).
let convert' str =
let strLen = String.length str
let sb = System.Text.StringBuilder strLen
let rec convertRec (count, idx) =
match strLen - idx with
| 0 ->
count, sb.ToString ()
| 1 ->
// Append the last character in the string to the StringBuilder.
sb.Append str.[idx] |> ignore
convertRec (count, idx + 1)
| _ ->
if str.[idx] = ' ' && str.[idx + 1] = ' ' then
convertRec (count + 1, idx + 2)
else
sb.Append str.[idx] |> ignore
convertRec (count, idx + 1)
// Call the internal, recursive implementation.
convertRec (0, 0)

Resources