This is code from Project Euler #8 in F#.
My issue is that I am reading in a large (1000-digit) number that is separated by \n new line characters. However, I am still getting errors even when I join the "string" on newline characters. I have approached it two different ways, but I am still arriving at the same error message.
open System;
open System.Text;
let path = "/Users/Arbin/Desktop/VS Code/F#/Project Euler/Largest Product in Series/largest_product_text_file"
//let monster_number = System.IO.File.ReadAllText path
let monster_number_array = System.IO.File.ReadAllLines path
let monster_number = String.Join("\n", System.IO.File.ReadAllLines path);
printfn "%s" monster_number
let adjacent n seq =
seq |> Seq.mapi (fun index value -> seq |> Seq.skip index |> (Seq.truncate n))
//Mapping numbers from string to integer64.
let seq_of_seq = (adjacent 13 monster_number) |> Seq.map (Seq.map (int64 << string))
//Iterating through a sequence of sequence (nested sequence)
seq_of_seq |> Seq.iter (fun x -> x |> Seq.iter (fun y -> printfn "Ar: %A" y))
Output:
<Sequence Integers>
System.FormatException: Input string was not in a correct format.
at Microsoft.FSharp.Core.LanguagePrimitives.ParseInt64(String s) in D:\a\_work\1\s\src\FSharp.Core\prim-types.fs:line 2414
at Microsoft.FSharp.Collections.Internal.IEnumerator.map#99.DoMoveNext(b& curr) in D:\a\_work\1\s\src\FSharp.Core\seq.fs:line 102
at Microsoft.FSharp.Collections.Internal.IEnumerator.MapEnumerator`1.System.Collections.IEnumerator.MoveNext() in D:\a\_work\1\s\src\FSharp.Core\seq.fs:line 84
at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc`2 action, IEnumerable`1 source) in D:\a\_work\1\s\src\FSharp.Core\seq.fs:line 596
at FSI_0001.it#20.Invoke(IEnumerable`1 x) in /Users/Arbin/Desktop/VS Code/F#/Project Euler/Largest Product in Series/largest_product_in_series.fsx:line 20
at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc`2 action, IEnumerable`1 source) in D:\a\_work\1\s\src\FSharp.Core\seq.fs:line 597
at <StartupCode$FSI_0001>.$FSI_0001.main#() in /Users/Arbin/Desktop/VS Code/F#/Project Euler/Largest Product in Series/largest_product_in_series.fsx:line 20
Stopped due to error
The number is:
73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450
When you call String.Join("\n", ...), you are inserting newline characters into the resulting string. Then, later on, you're invoking int64 << string on one of those newlines. But you can't convert a newline character into an integer. If you use "" as your separator in String.Join, rather than "\n", you won't have this problem. (Or just call String.Concat instead of String.Join.)
Related
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();
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
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.
I have a CSV file, where the fst column is a title and next 700+ columns are some int data.
Title D1 D2 D3 D4 .. D700
Name1 0 1 7 5 48
I try to use CsvProvider to read the file and then convert data to my custom type
type DigitRecord = { Title:string; Digits:int[] }
The problem is I don't know how to put all column data (except the first one with a title) into a int[] array.
let dataRecords =
CSV.Rows
|> Seq.map (fun record -> {Title = record.Title; Digits = ???})
I want to get a record with Title=Name1 and Digits=[|0,1,7,5...48|]
I'm newbie in F#, I'd be grateful for any help!
I think the easiest way is to use CsvParser like this:
let readData (path : string) seps =
CsvFile.Load(path, seps).Rows
|> Seq.map
(fun row -> row.Columns.[0], row.Columns |> Array.skip 1 |> Array.map int)
|> Seq.map
(fun (title, digits) -> {Title = title; Digits = digits})
The order of my Sequence, array etc matters. I have tried converting between List, Seq and Array to see if there are differences and in each case it inverses the order.
I have a seq of [noun] [verb] [ajective] for example, which is transformed into strings and then folded together. A sample response given this template might be "bad run bandits" instead of "bandits run bad".
Any thoughts on why fold does this or how to get it to execute in the appropriate order?
let res = template |> Seq.map(fun pos ->
let e = s |> PredictionEngine.GetRandom
pos |> PredictionEngine.GetBestPartOfSpeechWord e)
|> Seq.fold(fun acc w -> w.Text + " " + acc) ""
I believe this is just a matter of changing the order of your last function to:
Seq.fold(fun acc w -> acc + " " + w.Text) ""
Like this the new itens get concatenated to the end of the old ones. A minimum example of this working can be seen in the following snippet:
["Bandits";"Run";"Bad"]
|> Seq.fold(fun acc w -> acc + " " + w) ""
|> printfn "%s"
If you have such common job as concatenating strings I recommend using functions from library.
["noun"; "verb"; "adj"]
|> String.concat " "
On daily basis work, I think, there are not so many problems that require writing custom folding.
let x=[|15..20|]
let y=Array.map f x
printf "%O" y
Well, I got a type information.
Is there any way to print each element of "y" with delimiter of ",", while not having to use a for loop?
Either use String.Join in the System namespace or F# 'native':
let x = [| 15 .. 20 |]
printfn "%s" (System.String.Join(",", x))
x |> Seq.map string |> String.concat "," |> printfn "%s"
Using String.concat to concatenate the string with a separator is probably the best option in this case (because you do not want to have the separator at the end).
However, if you just wanted to print all elements, you can also use Array.iter:
let nums= [|15..20|]
Array.iter (fun x -> printfn "%O" x) nums // Using function call
nums |> Array.iter (fun x -> printfn "%O" x) // Using the pipe
Adding the separators in this case is harder, but possible using iteri:
nums |> Array.iteri (fun i x ->
if i <> 0 then printf ", "
printf "%O" x)
This won't print the entire array if it is large; I think it prints only the first 100 elements. Still, I suspect this is what you're after:
printfn "%A" y
If the array of items is large and you do not want to generate a large string, another option is to generate a interleaved sequence and skip the first item. The following code works assuming the array has at least one element.
One advantage of this approach is that it cleanly separates the act of interleaving the items and that of printing. It also eliminates having to do a check for the first item on every iteration.
let items = [| 15 .. 20|]
let strInterleaved delimiter items =
items
|> Seq.collect (fun item -> seq { yield delimiter; yield item})
|> Seq.skip(1)
items
|> Seq.map string
|> strInterleaved ","
|> Seq.iter (printf "%s")
I am trying to print a large list with F# and am a difficult time. I am trying to create a lexical analyzer in F# I believe I am done but I can't seem to get it to print the entire list to check it.
here is an example of what I am trying to do
let modifierReg = Regex("(public|private)");
let isModifier str = if (modifierReg.IsMatch(str)) then ["Modifier"; str] else ["Keyword"; str]
let readLines filePath = seq {
use sr = new StreamReader (filePath:string)
while not sr.EndOfStream do
yield sr.ReadLine () }
let splitLines listArray =
listArray
|> Seq.map (fun (line: string) -> let m = Regex.Match(line, commentReg) in if m.Success then (m.Groups.Item 1).Value.Split([|' '|], System.StringSplitOptions.RemoveEmptyEntries) else line.Split([|' '|], System.StringSplitOptions.RemoveEmptyEntries) )
let res =
string1
|> readLines
|> splitLines
let scanLines lexicons =
lexicons
|> Seq.map (fun strArray -> strArray |> Seq.map (fun str -> isModifier(str)))
let printSeq seq =
printfn "%A" seq
let scanner filePath =
filePath
|> readLines
|> splitLines
|> scanLines
let scannerResults = scanner pathToCode
printSeq scannerResults
When I try to print the list I get the following
seq
[seq [["Keyword"; "class"]; ["Identifier"; "A"]]; seq [["Block"; "{"]];
seq [["Modifier"; "public"]; ["Type"; "int"]; ["Identifier"; "x;"]];
seq [["Modifier"; "public"]; ["Type"; "int"]; ["Identifier"; "y;"]]; ...]
I can't get it to print any further. I get the same behavior with something as simple as the following
printfn "%a" [1 .. 101]]
I can't seem to figure out how to print it off. Anyone have any experience with this? I can't seem to find any examples
Seq.iter will iterate over all the elements of a sequence, so e.g.
somelist|> Seq.iter (printfn "%A")
will print each of the elements. (The "%A" specifier is good at the common case for printing arbitrary data, but for large lists or whatnot, you can exercise finer control, as here, by iterating over every element and printing each individually, e.g. on a new line as above.)
You're not working with lists, you're working with sequences. Since sequences may be infinite, printf and friends only output the first N elements. Makes sense.
Brain and Daniel has already answered your question. I would add that %A would use reflection to print the object passed to printfn function. In your case it is not simple list of items but rather a list of list of list and so on, which basically is a tree. If this tree is too large then printfn "%A" would be pose a performance problem and you would need to write your own print function that could traverse the tree and print it.