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 []
I am creating a tokenization system in Kotlin / JVM that takes in a file and returns each char or sequence of chars as a token. For some reason, whenever I tokenized a string, it finds the second instance of s "string" token before moving onto the next token, or in other words, the tokens are not in order. I think it might have to do with the loop, but I just can't figure it out. I am still learning Kotlin, so if anyone could give me pointers as well, that'd be great! Much appreciated any help.
output of tokens :
[["chello", string], ["tomo", string], [:, keyV], ["hunna", string], ["moobes", string], ["hunna", string]]
My file looks like this.
STORE "chello" : "tomo" as 1235312
SEND "hunna" in Hollo
GET "moobes"
GET "hunna"
fun tokenCreator (file: BufferedReader) {
var lexicon : String = file.readText()
val numRegex = Regex("^[1-9]\\d*(\\.\\d+)?\$")
val dataRegex = Regex("[(){}]")
val token = mutableListOf<List<Any>>()
for((index, char) in lexicon.withIndex()) {
println(char)
when {
char.isWhitespace() -> continue
char.toString() == ":" -> token.add(listOf(char.toString(), "keyV") )
char.toString().matches(Regex("[()]")) -> token.add(listOf(char, "group") )
char.toString().matches(dataRegex) -> token.add(listOf(char, "data_group" ) )
char == '>' -> token.add(listOf(char.toString(), "verbline") )
char == '"' -> {
var stringOf = ""
val firstQuote = lexicon.indexOf(char)
val secondQuote = lexicon.indexOf(char, firstQuote + 1)
if(firstQuote == -1 || secondQuote == -1) {
break
}
for(i in firstQuote..secondQuote) {
stringOf += lexicon[i]
}
lexicon = lexicon.substring(secondQuote + 1, lexicon.length)
token.add(listOf(stringOf, "string"))
}
}
}
println(token)
}
Changing the content while iterating seems like a recipe for confusion...
And you don't seem to increment the index to skip over consumed content. I'd recommend to change the loop in a way that allows you to skip over content you have consumed
I'd also remove this line:
lexicon = lexicon.substring(secondQuote + 1, lexicon.length)
Then replace
val firstQuote = lexicon.indexOf(char)
with
val firstQuote = index
You can also use substring instead of iteration for stringOf
val stringOf = lexicon.substring(
Moreover, using toString to check for ':' seems inefficient
I've read a text file into a big string:
fileText = try NSString(contentsOfFile: pathToFile, encoding: String.Encoding.utf8.rawValue) as String
(I omitted the do/catch part and fileText was declared as an optional string constant before the assignment).
Now I split the lines out into an array of strings, trim the whitespace from each, and then remove any empty strings:
let lines = (fileText!.components(separatedBy: "\n")).map { $0.trimmingCharacters(in: .whitespaces)}.filter {$0.count > 0}
And it works fine, but I'm learning Swift 4 and I suspect there's a cleaner way to accomplish my task, right? I would appreciate any examples that put my code to shame. Thanks!
Problem of your code, is that you iterate through all String charecters for four times. But task can be complete only iterating once. Something like this:
let myString = String() // String received from any source
var lines = [String]()
var line = ""
myString!.forEach {
switch $0 {
case " ":
break
case "\n":
if line.count > 0 {
lines.append(line)
line = ""
}
default:
line += String($0)
}
}
print(lines)
For test file:
$ cat test.txt
123123123 12312312
123 12312312 12312312
sfsdfsdfsfsdf
sdfsdf 23234 sdfsdfs 23234
sdfsdf
sdfsdfsdf
Result will be:
$ swift main.swift
["12312312312312312", "1231231231212312312", "sfsdfsdfsfsdf", "sdfsdf23234sdfsdfs23234", "sdfsdf", "sdfsdfsdf"]
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") })
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).