need help to read file with specific formatted contents - f#

i'm using F#. I want to solve some problem that require me to read the input from a file, i don't know what to do. The first line in the file consist of three numbers, the first two numbers is the x and y for an map for the next line. The example file:
5 5 10
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
the meaning of 5 5 10 is the next line have 5x5 map and 10 is just some numbers that i need to solve the problem, the next until the end of the line is contents of the map that i have to solve using the 10 and i want to save this map numbers in 2 dimensional array. Someone can help me to write a code to save the all the numbers from the file so i can process it?
* Sorry my english is bad, hope my question can be understood :)
The answer for my own question :
Thanks for the answer from Daniel and Ankur. For my own purpose i mix code from both of you:
let readMap2 (path:string) =
let lines = File.ReadAllLines path
let [|x; y; n|] = lines.[0].Split() |> Array.map int
let data =
[|
for l in (lines |> Array.toSeq |> Seq.skip 1) do
yield l.Split() |> Array.map int
|]
x,y,n,data
Many Thanks :D

Here's some quick and dirty code. It returns a tuple of the last number in the header (10 in this case) and a two-dimensional array of the values.
open System.IO
let readMap (path:string) =
use reader = new StreamReader(path)
match reader.ReadLine() with
| null -> failwith "empty file"
| line ->
match line.Split() with
| [|_; _; _|] as hdr ->
let [|x; y; n|] = hdr |> Array.map int
let vals = Array2D.zeroCreate y x
for i in 0..(y-1) do
match reader.ReadLine() with
| null -> failwith "unexpected end of file"
| line ->
let arr = line.Split() |> Array.map int
if arr.Length <> x then failwith "wrong number of fields"
else for j in 0..(x-1) do vals.[i, j] <- arr.[j]
n, vals
| _ -> failwith "bad header"

In case the file is this much only (no further data to process) and always in correct format (no need to handle missing data etc) then it would be as simple as:
let readMap (path:string) =
let lines = File.ReadAllLines path
let [|_; _; n|] = lines.[0].Split() |> Array.map int
[|
for l in (lines |> Array.toSeq |> Seq.skip 1) do
yield l.Split() |> Array.map int
|]

Related

Drop duplicates except for the first occurrence with Deedle

I have a table with one key with duplicate values. I would like to drop/reduce all duplicate keys but preserve the first row of each duplicate.
let data = "A;B\na;1\nb;\nb;2\nc;3"
let bytes = System.Text.Encoding.UTF8.GetBytes data
let stream = new MemoryStream( bytes )
let df=
Frame.ReadCsv(
stream = stream,
separators = ";",
hasHeaders = true
)
df.Print()
A B
0 -> a 1
1 -> b <missing>
2 -> b 2
3 -> c 3
The result should be
A B
0 -> a 1
1 -> b <missing>
2 -> c 3
I have tried applyLevel but I only get the value not the first entry:
let df1 =
df
|> Frame.groupRowsByString "A"
|> Frame.applyLevel fst (fun s -> s |> Series.firstValue)
df1.Print()
A B
a -> a 1
b -> b 2 <- wrong
c -> c 3
This is essentially a duplicate of a previous SO question. The short answer is:
let df1 =
df
|> Frame.groupRowsByString "A"
|> Frame.nest // convert to a series of frames
|> Series.mapValues (Frame.take 1) // take the first row from each frame
|> Frame.unnest // convert back to a single frame
|> Frame.mapRowKeys snd
df1.Print()
The output is:
A B
0 -> a 1
1 -> b <missing>
3 -> c 3
I've added a call to Frame.mapRowKeys at the end to match your desired output as closely as possible. Note that the actual output differs slightly from your expected output, because row 3 -> c 3 has original index 3 instead of 2. I think this is more correct, but you can renumber the rows if necessary.
The referenced question has more details.
Using Frame.nest/Frame.unnest is a reasonable solution. I have noticed, it is a little bit slow.
My solution involves putting the keys in a Map and checking:
let dropDuplicates (df:Frame<_,_>) =
let selectedMap =
df.RowKeys
|> Seq.fold (fun (m:Map<'A,'B>) (a,b) ->
if m.ContainsKey a then m else m |> Map.add a b) Map.empty
df
|> Frame.filterRows(fun (a,b) _ ->
match selectedMap.TryFind a with
| Some entry -> entry = b
| _ -> false)
let df1 =
df
|> Frame.groupRowsByString "A"
|> dropDuplicates
df1.Print()
A B
a 0 -> a 1
b 1 -> b <missing>
c 3 -> c 3

F# problems calling a function that takes a integer and return a string

I'm pretty new to programming in F#, and I am working on a project at the moment, with a function that takes an integer and returns a string value.
My problem (se my code below) is that no matter what I do, I cant return the values of my str, calling my function.
let mulTable (n:int):string = string n
let mutable m = 1
let mutable str = ""
while m < 10 do
str <- "m\t" + str
m <- m + 1
printfn "%A" (mulTable str)
My idea here is that I want to store the value of m, in str, så that str in the end of my while loop contains the values of "1 2 3 4 5 6 7 8 9". But no matter what I try my printfn "%A" mulTable str, returns "this expressions was exspected to have type int, but here has type string". I have tried converting my str to a string in my mutable value like:
let mutable str = ""
let mutable str1 = str |> int
and then I try to call my str1 using function mulTable instead of calling str. But still it does not work.
What am I missing here? I've been trying every single possible solution I can think of, without being able to solve my problem.
A fix of your own algorithm could be:
let getSequenceAsString max =
let concat s x = sprintf "%s\t%i" s x
let mutable m = 1
let mutable str = ""
while m < max do
str <- concat str m
m <- m + 1
str
printfn "%A" (getSequenceAsString 10)
But as others have shown it's a lot of work that can be done more easily:
open System
let getSequenceAsString max =
String.Join("\t", [1..max-1])
If you want each number reverted as you ask for in a comment it could be done this way:
let getSequenceAsString min max =
let revert x =
let rec rev y acc =
match y with
| 0 -> acc
| _ -> rev (y / 10) (sprintf "%s%i" acc (y % 10))
rev x ""
String.Join("\t", ([min..max-1] |> List.map revert))
printfn "%A" (getSequenceAsString 95 105)
Gives:
"59 69 79 89 99 001 101 201 301 401"
You can easily join an array of strings into a string array, and then print it out if necessary.
open System
let xs = [1..9] |> List.map string
//you should avoid using mutable variables, and instead generate your list of numbers with an list comprehension or something similar.
String.Join("\t", xs)
//A little exploration of the List/Array/String classes will bring this method up: "concatenates the members of a collection using the separator string.
This gives me:
val it : string = "1 2 3 4 5 6 7 8 9"
I've adjusted the code to make it produce results similar to what you wanted:
let mulTable (n:int):string = string n
let mutable m = 1
let mutable str = ""
while m < 10 do
str <- mulTable m+ "\t" + str
m <- m + 1
printfn "%A" (str)
I've used your mulTable to convert m to string, but for printfn you don't need to use that, because str is already a string.
Still the result would be 9 8 7 6 5 4 3 2 1
There are more then one way to revert the string, one of them would be to split the string into an array of characthers and then revert the array. From resulting array we will build a new string again. It would look something like:
printf "%A" (new System.String(str.ToCharArray() |> Array.rev ))
Edit
To achieve the same result, I would suggest to use more functional style, using recursion and avoiding mutating variables.
let getNumbersString upperLimit =
let rec innerRecursion rem acc=
match rem with
| 0 -> acc
| _ -> innerRecursion (rem-1) (sprintf "%i "rem::acc)
innerRecursion upperLimit [] |> String.concat ""
getNumbersString 9
Will result in
val it : string = "1 2 3 4 5 6 7 8 9 "

Matrix transposition in F#

I'm trying to modify a matrix like this one:
/ 1 2 3 \
\ 4 5 6 /
to return:
/ 1 4 \
| 2 5 |
\ 3 6 /
Instead it is flipping my matrix by the corners. This is the code I have so far:
Let rec matrixadjust = function
| (_::_) : : as xss-> List.map List.head xss :: matrixadjust (List.map List.tail xss)
| _ ->[];;
I think that the best way to work with matrix is using the Array2D data structure. You can build an Array2D from an array of arrays and then create a new Array2D to acomplish what you want:
let arrayOfArrays = [| [| 1; 2; 3 |]; [|4; 5; 6 |] |]
let array2d = Array2D.init 2 3 (fun row column -> arrayOfArrays.[row].[column])
let newArray = Array2D.init (array2d |> Array2D.length2) (array2d |> Array2D.length1) (fun r c -> array2d.[c,r])
Assuming your data structure is a list of lists where each sub-list represents a row you could do it like this. Basically it loops once per source-list row and accumulates the result in the partial binding. Since its doing list accumulation, it reverses the order of the values so you have to do a List.rev on each row at the end.
let flip matrix =
match matrix with
| [] -> []
| x::xs ->
let rec loop matrix partial =
match matrix with
| [] -> partial
| y::ys ->let newPartial = (y, partial) ||> List.map2(fun x y->x::y)
loop ys newPartial
let length = List.length x
loop matrix (List.init length (fun _ -> [] ))
|> List.map(fun x->x |> List.rev)

how to read file and skip some white spaces

this is similiar to my previous question,
but there is another improvisation, how is the code if i want to skip some white spaces, for this case is "enter", for example:
5 5 10
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
<- this white space
3 4 4
1 2 3 4
1 2 3 4
1 2 3 4
i try to my best but couldn't find how to skip the white space
thank you for the help :)
This is the answer, thanks to Ramon :
let readMap (path:string) =
let lines = File.ReadAllLines path
let [|x; y; n|] = lines.[0].Split() |> Array.map int
let data =
[|
for l in (lines |> Array.toSeq |> Seq.skip 1 |> Seq.filter(System.String.IsNullOrEmpty >> not)) do
yield l.Split()
|]
x,y,n,data
Another way to write your readMap function is to use if expression inside the list comprehension. I think this is actually more readable if you're using comprehensions (because you don't have to combine two ways of writing things):
let readMap (path:string) =
let lines = File.ReadAllLines path
let [|x; y; n|] = lines.[0].Split() |> Array.map int
let data =
[|
for l in lines |> Seq.skip 1 do
if not (System.String.IsNullOrEmpty(l)) then
yield l.Split()
|]
x,y,n,data
I also removed the call to Array.toSeq, because F# allows you to use array in a place where seq is expected without an explicit conversion (seq is actually IEnumerable and array implements it).
What about this:
val items : string list
items
|> List.filter (System.String.IsNullOrEmpty >> not)
?

Char value in F#

Lets say I have a string "COLIN".
The numeric value of this string would is worth:
3 + 15 + 12 + 9 + 14 = 53.
So
A = 1, B = 2, C = 3, and so on.
I have no idea how to even start in F# for this.
let mutable nametotal = 0
let rec tcalculate name =
name.ToString().ToCharArray()
|> Seq.length
Here is what I have so far. The seq.length is just there for testing to see if the toCharArray actually worked.
What you have is decent; here's another version:
#light
let Value (c:char) =
(int c) - (int 'A') + 1
let CalcValue name =
name |> Seq.sum_by Value
printfn "COLIN = %d" (CalcValue "COLIN")
// may be of interest:
printfn "%A" ("COLIN" |> Seq.map Value |> Seq.to_list)
It assumes the original input is uppercase. "int" is a function that converts a char (or whatever) to an int; Seq.sum_by is perfect for this.
I also show an example of using map, not sure what you're interested in.
If the 'mapping' is more arbitrary, you could use a strategy like the code below, where you can specify a data structure of what value each letter maps to.
#light
let table = [
'C', 3
'O', 15
'L', 12
'I', 9
'N', 14
]
let dictionary = dict table
let Value c =
match dictionary.TryGetValue(c) with
| true, v -> v
| _ -> failwith (sprintf "letter '%c' was not in lookup table" c)
let CalcValue name =
name |> Seq.sum_by Value
printfn "COLIN = %d" (CalcValue "COLIN")
I've found a hackish way to do this using the ascii value of the character, and getting the number from there but i think there might be a better way.
let tcalculate name =
name.ToString().ToLower().ToCharArray()
|> Seq.map (fun char -> Convert.ToInt32 char - 96)
|> Seq.sum
work's beautifully and maybe even more efficient then "mapping" but I'd like to view the solution I asked for
thanks all.
all you need to do, is make the string lowercase, turn it into a char array like you have done, loop through each letter, take the value of each char and subtract the value of 'a' and add one. that will make each letter have the value of its position in the alphabet.
I realize this is very old but I am recently learning F# and playing with the ideas in this question. Maybe someone will find it useful:
let table =
Seq.zip ['A'..'Z'] (Seq.initInfinite((+) 1))
|> Map.ofSeq
let calc (input : string) =
let s = input.ToUpper()
match s with
| _ when Seq.forall System.Char.IsLetter s ->
Some (Seq.sumBy (fun c -> table.[c]) s)
| _ -> None
let sumOfChar name = // F# functional answer
name
|> List.ofSeq // to char array
|> List.map (fun c -> int (System.Char.ToUpper c) - int 'A' + 1) // to value
|> List.fold (+) 0 // sum
sumOfChar "Herb" // 33
// Or simply this version:
let sumOfCharBy name =
let value c = int (System.Char.ToUpper c) - int 'A' + 1
List.sumBy value (List.ofSeq name)
sumOfCharBy "HerbM" // 46
// or simply:
let sumOfCharBy name =
name |> Seq.sumBy (fun c -> int (System.Char.ToUpper c) - int 'A' + 1)
sumOfCharBy "HMartin" // 83

Resources