How do I write in text file, when I've created a file

Viewed 75

this is my first time writing in here. I'm new to f# and wanted to get some help. I've made a program that's supposed to take words out of an existing text file, edit it and write it in a new text file, in order by most frequent word to least. I've made the most, but when the text file appears, but inside it says:

System.Tuple`2[System.String,System.Int32][]

Here's my code:

let reg = RegularExpressions.Regex "\s+" 
let cleanEx = RegularExpressions.Regex "[\,\.\!\"\:\;\?\-]" 
let read = (File.OpenText "clep.txt").ReadToEnd() 
let clen = (cleanEx.Replace(read, "")).ToLower() 

let clean = reg.Split(clen)
let finAr = Array.countBy id clean
let finlist = Array.sortByDescending (fun (_, count) -> count) finAr
// printfn "%A" finlist


let string = finlist.ToString()
let writer = File.AppendText("descend.txt")
writer.WriteLine(finlist);
writer.Close();
2 Answers

You're only writing a single line of text to the file, and because finlist is not a type for which StreamWriter.WriteLine() has a specific overload, it is treated as object, and the string used is the result of finlist.ToString(), which, as is common with built-in .NET types, is just the type name.

If you want to write the actual elements of the array to the file, you need to actually process the array.

This would write the string parts from all the tuples to the text file:

finlist
|> Array.map fst
|> Array.iter writer.WriteLine

To include the numbers, for example in the format "text: 1", you would have to create an appropriately formatted string for each array item first:

finlist
|> Array.map (fun (text, number) -> sprintf "%s: %i" text number)
|> Array.iter writer.WriteLine

By the way, because of the way .NET strings use \ for escaping characters, just like regular expressions do, your RegExes won't work the way you've written them. It should be

let reg = RegularExpressions.Regex @"\s+"
let cleanEx = RegularExpressions.Regex @"[\,\.\!\""\:\;\?\-]"

There are two changes here: The @ before the strings tell the compiler not to use \ to escape characters (alternatively you can write every single backslash in a RegEx as \\, but that doesn't make it any more readable). In the middle of the second one, another " escapes the double quotes, because otherwise they would now terminate the string, and the line wouldn't compile anymore.

Why do you see?

System.Tuple`2[System.String,System.Int32][]

Because finAr is an array of tuples (string*int) and finlist is the array of same items, but ordered by count. When you do finlist.ToString() it does not give you a string representation of array items. ToString() by default (if not overridden) return full name of the object type. Which is array of tuples in your case.

Now what do you need to write a file of words in the frequency order? Just mapping array items to strings:

let lines =
   clean
   |> Array.countBy id // finAr
   |> Array.sortByDescending (fun (_,count) -> count) // finlist
   |> Array.map (fun (word, _) -> word) // here mapping each tuple to string

File.WriteAllLines("descent.txt", lines)

With a couple of wrappers, you can pipe operations related to reading file and writing to file:

"clep.txt"
|> readTextFile
|> getWordsMostFrequestFirst
|> writeLinesToFile "descent.txt"

Wrappers:

let readTextFile (path: string) =
    (File.OpenText path).ReadToEnd()

let writeLinesToFile (path: string) (contents: string seq) =
    File.WriteAllLines(path, contents)

And a function which processes text:

let getWordsMostFrequestFirst (text: string) =
    let splitByWhitespaces (input: string) = Regex.Split(input, "\s+")
    let toLower (input: string) = input.ToLower()
    let removeDelimiters (input: string) = Regex.Replace(input, "[\,\.\!\"\:\;\?\-]", "")

    text
    |> removeDelimiters
    |> toLower
    |> splitByWhitespaces
    |> Array.countBy id
    |> Array.sortByDescending snd // easy way to get tuple items
    |> Array.map fst
Related