Reading integers from file OCaml - file

I have to read integers from a "file.txt" in OCaml and store them in a list. I have tried to read with stdlib but it does not work. Also I cannot understand how scanf works for files. If someone could help me with scanf i would be grateful.
Edit
Sorry for not being clear enough, first time posting. The input format is a b c\n
d e f\n
...
Yes it is for my university. Basically i have to find mst of a graph. The input is vertex_1 vertex_2 weight \n and so on and i am trying to build a list of tuples [(vertex_1 vertex_2 weight),...] from input. In my code i am trying to gather chars to a string if its needed (ex two digit numbers) and then converting string to int. But i hope there is an easier way of doing that. I have to say that is the second day that i am programming in ocaml.
let entry_of_channel ch =
let number = input_char ch in number
let rec list_of_channel ch =
try
let e = entry_of_channel ch in
e:: list_of_channel ch
with
End_of_file -> []
let string_of_chars chars =
let buf = Buffer.create 16 in
List.iter(Buffer.add_char buf) chars
let rec list_clear list buffer =
match list with
[] -> []
|' '::t -> (string_of_chars buffer)::list_clear t []
|'\n'::t ->(string_of_chars buffer)::list_clear t []
|h::t -> buffer # h;
list_clear t buffer
let graph filename =
let ch = open_in filename in
let l = list_of_channel ch in
close_in ch;
let l_new = list_clear l [] in
l_new

Since this is presumably for a school assignment, you should ideally show some code you've written and ask for help with a specific problem. However, reading integers from a file is probably not the interesting part of the assignment.
You don't give any information about the format of the file. Here's a function that reads whatever integers it finds on lines in a file, separated by spaces and tabs:
let read_ints filename =
let inchan = open_in filename in
let spre = Str.regexp "[ \t]+" in
let rec loop accum =
match input_line inchan with
| line ->
let wds = Str.split spre line in
loop (List.rev (List.map int_of_string wds) # accum)
| exception End_of_file ->
close_in inchan;
List.rev accum
in
loop []
Note that this does not handle errors. If the file can't be opened, or if there are non-integer values in the file, the code will raise an exception.
Here is a similar function that uses Scanf.fscanf:
let read_ints filename =
let inchan = open_in filename in
let rec loop accum =
match Scanf.fscanf inchan " %d" Fun.id with
| n -> loop (n :: accum)
| exception End_of_file ->
close_in inchan;
List.rev accum
in
loop []

Related

How to output a list of strings into a file with printf

I aim to write a function to read a string list persons with open_out and store it in the file filename
I tried to iterate over it with List.fold_left and use printf, however it is not working.
let write_list filename persons =
let file = open_out filename in
let write_person p =
let rec ite_pres aux acc = List.fold_left (Printf.fprintf file "%s\n" filename )
List.iter write_person persons;
close_out
Since you want to print one line by file List.iter is enough:
let chan =
List.iter (Printf.fprintf chan "%s\n") persons
With OCaml 4.14 and later version, you can also use with_open_text which opens and close the file channel by itself:
let write_list filename persons =
Out_channel.with_open_text filename (fun chan ->
List.iter (Printf.fprintf chan "%s\n") persons
)
with_
You don't need to mess with folds, or even with the Printf module, if all you want to do is write a string list to a file, one element per line. For example:
(* Like print_endline but for arbitrary output channels *)
let output_endline chan s = output_string chan s; output_char chan '\n'
(* Open a file and call f with the output channel as its argument.
* Note: Available as Out_channel.with_open_text in Ocaml 4.14 and newer *)
let with_open_text filename f =
let chan = open_out filename in
try
f chan; close_out chan
with x -> close_out chan; raise x
let print_list_to_file filename slst =
with_open_text filename (function chan -> List.iter (output_endline chan) slst)
let _ = print_list_to_file "output.txt" ["a";"b";"c"]
This defines a couple of handy convenience functions, and uses with them List.iter to print out the list.

Compare two files in Erlang

I have two different files. First file look like this:
hallo
bye
something
new
And in second file I have eg. bye. From name of second file (eg. msg-0002) I know that this message must be second in first file. How can I, in Erlang, find that particularly word in first file? I just have to see if the second word is really bye.
That's the code I made so far:
-module(compare).
-export([compare/0]).
compare () ->
{ok, Pars} = file:read_file("words.txt"),
{ok, Dump} = file:read_file("msg-0002.file"),
L1 = binary:split(Pars, <<"\n">>, [global]).
L2 = binary:split(Dump, <<"\n">>, [global]).
In this code I get all the words in lists. I don't know how to get from name of msg-0002 file that word must be in 2. place in first file. And how to check if this particularly word is really in eg. second place in first file? That's important.
to extract the line number from the file name (assuming the file names are always of the form "msg-XXX.file":
FileName = "msg-0002.file",
{ok,[NumLine],_} = io_lib:fread("msg-~d.file",FileName),
and then to check if the 2 files are consistent, use Dogbert proposal:
{ok, Pars} = file:read_file("words.txt"),
{ok, Dump} = file:read_file(FileName),
L1 = binary:split(Pars, <<"\n">>, [global]),
L2 = binary:split(Dump, <<"\n">>, [global]),
Check = lists:nth(NumLine, L1) == lists:nth(1, L2),
...
There are many ways how you can do it, for example in escript:
#!/usr/bin/env escript
main(["-q"|ARGS]) ->
compare(ARGS, true);
main(ARGS) ->
compare(ARGS, false).
compare([MsgFile, WordsFile], Quiet) ->
case io_lib:fread("msg-~d", MsgFile) of
{ok, [N], _} when N > 0 ->
Msg = read_msg(MsgFile),
Word = read_nth(WordsFile, N),
case Msg =:= Word of
true ->
Quiet orelse io:put_chars("Yes\n"),
halt(0);
false ->
Quiet orelse io:put_chars("No\n"),
halt(1)
end;
_ -> usage()
end;
compare(_, _) ->
usage().
read_msg(File) ->
{ok, FH} = file:open(File, [read, binary]),
{ok, Msg} = file:read_line(FH),
ok = file:close(FH),
Msg.
read_nth(File, N) ->
{ok, FH} = file:open(File, [raw, read, binary, read_ahead]),
Word = read_nth_(FH, N),
ok = file:close(FH),
Word.
read_nth_(FH, N) ->
case file:read_line(FH) of
{ok, Word} when N =:= 1 -> Word;
{ok, _} -> read_nth_(FH, N-1);
Error -> error({words_file, Error})
end.
usage() ->
io:format(standard_error, "~ts [-q] <msg-file> <words-file>~n"
"\t<msg-file> - must have name in form msg-N*~n",
[escript:script_name()]),
halt(255).

how to delete an element that contains a letter in array using swift

I am having trouble trying to figure this topic out. Like the topic, How do I delete an element that contains a letter in Array. This is the code I have so far.
let newline = "\n"
let task = Process()
task.launchPath = "/bin/sh"
task.arguments = ["-c", "traceroute -nm 18 -q 1 8.8.8.8"]
let pipe = Pipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
var array = output.components(separatedBy: " ")
array = array.filter(){$0 != "m"}
print(array, newline)
I have tried multiple options given by this stack overflow.
How to remove an element from an array in Swift
I think I have hit a wall.
Have you tried
array = array.filter({ !$0.contains("m") })

2 dimension array processing in haskell

Sorry for my question which might seem trivial to some (I'm new). I have a file which contains a map looking like this :
---#--###----
-#---#----##-
------------#
In this file, – characters indicate that you are free to move in this direction. The # character indicates that you cannot move any further in this direction and you should go somewhere else. The # character indicates the location of the treasure. In this case, it is in the bottom right corner, but it could be anywhere in the map. So I have to go through these lines and see if I can reach the #. Here we are starting at the top left corner. So far I have managed to read the content of the file. And I'm wondering how to process this in Haskell. It will be easy in Java using a 2-dimensional array but how can I appproach this problem in Haskell?
For example, for the previous example, the path is:
+++#--###----
-#+--#----##-
--++++++++++#
The + symbol represents the path to the # symbol.
This the algorithm I have to implement it in Java:
Dfs(i,j) {
if (arr[i][j+1] == "-" && i >=0 && i<=row.size && j>=0 && j<=column.size) {
Dfs(i,j+1)
} else if(arr[i][j+1] == "#") {
}
if (arr[i][j-1] == "-" && i >=0 && i<=row.size && j>=0 && j<=column.size) {
Dfs(i,j-1)
} else if(arr[i][j-1] == "#") {
}
if (arr[i+1][j] == "-" && i >=0 && i<=row.size && j>=0 && j<=column.size) {
Dfs(i+1,j)
} else if(arr[i+1][j] == "#") {
}
}
Thank you
There are many ways of making 2D arrays in Haskell, here is a somewhat laborious example of reading the chars into a Data.Array array, and then moving things about with the so-called state monad:
import Data.Array
import Control.Monad.State.Strict
main = do str <- getContents -- accepts string from stdin
let array = mkThingArray str -- we parse the string
limits = snd (bounds array) -- we remember (height,width)
initialState = ((0::Int,-1::Int),limits,array)
((position,(h,w),a)) <- execStateT findpath initialState
let chars = elems $ fmap toChar a
putStrLn ""
putStrLn $ splitText (w+1) chars
parseArray str = listArray ((0,0),(height-1, width-1)) total where
rawlines = lines str
ls = filter (not . null) rawlines
lens = map length ls
height = length ls
width = minimum lens
proper = map (take width) ls
total = concat proper
data Thing = Open | Closed | Home | Taken deriving (Show, Eq, Ord)
toThing c = case c of '-' -> Open; '#' -> Closed; '#' -> Home;
'+' -> Taken; _ -> error "No such Thing"
toChar c = case c of Open -> '-'; Closed -> '#';
Home -> '#'; Taken -> '+'
mkThingArray str = fmap toThing (parseArray str)
And continuing with an absurdly primitive 'logic' of state change:
-- we begin with moveright, which may then pass on to movedown
-- and so on perhaps in a more sophisticated case
findpath = moveright
where
moveright = do ((n,m), (bound1,bound2), arr) <- get
if m < bound2
then case arr ! (n,m+1) of
Open -> do liftIO (putStrLn "moved right")
put ((n,m+1), (bound1,bound2), arr // [((n,m+1),Taken)])
moveright
Closed -> movedown
Home -> return ()
Taken -> movedown
else movedown
movedown = do ((n,m), (bound1,bound2), arr) <- get
if n < bound1
then case arr ! (n+1,m) of
Open -> do liftIO (putStrLn "moved down")
put ((n+1,m), (bound1,bound2), arr // [((n+1,m),Taken)])
moveright
Closed -> moveright
Home -> return ()
Taken -> moveright
else moveright
splitText n str = unlines $ split n [] str
where split n xss [] = xss
split n xss str = let (a,b) = splitAt n str
in if not (null a)
then split n (xss ++ [a]) b
else xss
which, in this happy case, gives output like this
{-
$ pbpaste | ./arrayparse
moved right
moved right
moved right
moved down
moved right
moved right
moved down
moved right
moved right
moved right
moved right
moved right
moved right
moved right
+++#--###----
-#+++#----##-
----++++++++#
-}
The logic will have to be more sophisticated, with moveleft and moveup, etc., etc. but this is supposed to give the idea, or an idea.
Edit: Here is a version that doesn't use an intermediate type and doesn't throw any IO into the state machine. It should be more usable in ghci, so you can tear it apart more easily:
import Data.Array
import Control.Monad.Trans.State.Strict
main = do str <- readFile "input.txt"
((pos,(h,w),endarray)) <- execStateT findpath
(mkInitialState str)
putStrLn $ prettyArray endarray
-- the following are just synonyms, nothing is happening:
type Pos = (Int, Int) -- Our positions are in 2 dimensions
type Arr = Array Pos Char -- Characters occupy these positions
type ArrState = (Pos, Pos, Arr) -- We will be tracking not just
-- an array of Chars but a
-- current position and the total size
parseArray :: String -> Arr
parseArray str = listArray ((1,1),(height, width)) (concat cropped) where
ls = filter (not . null) (lines str)
width = minimum (map length ls)
height = length ls
cropped = map (take width) ls -- the map is cropped to shortest line
prettyArray :: Arr -> String
prettyArray arr = split [] (elems arr)
where (ab,(h,w)) = bounds arr
split xss [] = unlines xss
split xss str = let (a,b) = splitAt w str
in if null a then unlines xss else split (xss ++ [a]) b
mkInitialState :: String -> ArrState
mkInitialState str = ((1::Int,0::Int), limits, array)
where array = parseArray str -- we parse the string
limits = snd (bounds array) -- we remember (height,width)
-- since we don't resize, tracking this could be avoided
makeStep :: Arr -> Pos -> Arr
makeStep arr (n, m) = arr // [((n,m),'+')] -- this is crude
moveRight, moveDown, findpath :: Monad m => StateT ArrState m ()
moveRight = do ((n,m),bounds,arr) <- get
put ((n,m+1), bounds, makeStep arr (n,m+1))
moveDown = do ((n,m),bounds,arr) <- get
put ((n+1,m), bounds, makeStep arr (n+1,m))
findpath = tryRight
where -- good luck for most paths ...
tryRight = do ((n,m), (_,bound2), arr) <- get
if m < bound2
then case arr ! (n,m+1) of
'#' -> return ()
'-' -> do moveRight
tryRight
_ -> tryDown
else tryDown
tryDown = do ((n,m), (bound1,_), arr) <- get
if n < bound1
then case arr ! (n+1,m) of
'#' -> return ()
'-' -> do moveDown
tryRight
_ -> tryRight
else tryRight
runInput :: String -> String
runInput str = prettyArray endarray
where ((position,(h,w),endarray)) = execState findpath (mkInitialState str)
-- If I wanted to include IO things in the state machine,
-- I would have to use execStateT not execState, which presupposes purity
test :: String -> IO ()
test str = putStrLn (runInput str)
t1 = unlines ["---#--###----"
, ""
, "-#---#----##-"
, ""
, "------------#"
] :: String
--
t2 = unlines ["---#--###----"
,""
,"---#-#----##-"
,""
,"------------#"
] :: String
This very much depends on the way you want to use your 2D array.
If you only care about sequential use, a simple list of lists (basically [[Char]]) may be fine.
If you care about efficient getting to particular random coordinates, I can imagine that an IntList IntList Char could work for you; it's almost like list of lists, but individual cells can be much more efficiently updated, and it gives cheap random access for pathfinding.
Possibly a zipper-like structure would suit you best. I can't (so far) imagine a nice structure of this type that gives you both cheap (O(1) per neighbor cell) navigation for pathfinding and cheap updates.
Also, you could use a mutable map via Monad.Control.State e.g. by keeping a Data.Array in it, but you will have to lift all your logic into this monad (which would complicate passing copies of the map around, when you need it).

Ocaml Pretty slow file reader

I have the following code to read a file, which delete every comments in the file.
let s_read_all line =
if line = "" then
raise Pbm_format_error
else if line.[0] = '#' then
""
else
line ^ "\n"
;;
let read_all flec =
let rec loop accum_ref =
let line = input_line flec in
accum_ref := (!accum_ref) ^ (s_read_all line);
loop accum_ref
in
let accum_ref = ref "" in
try
loop accum_ref
with
End_of_file -> !accum_ref
;;
My code is really slow for a 180k line (about 2 minutes). I execute it in the interpretor mode. Is that which make my code so slow ?
The problem is that string concatenation is slow. More precisely, its repeteted string concatenation that is slow. You should use Buffer instead of string for accumulating lines:
let read_all flec =
let rec loop buffer =
let line = input_line flec in
Buffer.add_string buffer (s_read_all line);
loop buffer
in
let buffer = Buffer.create 180 in
try
loop buffer
with
End_of_file -> Buffer.content buffer
;;
You are using line ^ "\n" and (!accum_ref) ^ (s_read_all line);.
Like in Java, ^ is direct concat and will constantly create new strings. So i guess this is why it is slow for 180K lines.
You should use Buffer, just like StringBuilder in Java.
Also if you give a good initial length to Buffer.create, it will be slightly faster.
exception Pbm_format_error
let s_read_all line =
if line = "" then
raise Pbm_format_error
else if line.[0] = '#' then
""
else
line
let read_all flec =
let rec loop accum_buf =
let line = s_read_all (input_line flec) in
Buffer.add_string accum_buf line;
if line <> "" then Buffer.add_string accum_buf "\n" else ();
loop accum_buf
in
let accum_buf = Buffer.create (180 * 1000 * 128) in
try
loop accum_buf
with
End_of_file -> Buffer.contents accum_buf

Resources