I've been playing with Haskell and writing some code to parse DICOM medical images. The code is here. I wanted to create a function that will take in a ByteString and return a name. So a certain ByteString (actually two Int64s taken from a ByteString) would return PatientName or StudyDate for example. There are thousands of these and they are all contained within an XML file. So to create the function I parse the XML file and generate the desired function and output to a file using
writeTagNameFromElemGroup :: FilePath -> [(String,String,String,String)] -> IO()
writeTagNameFromElemGroup fp tups = init >> Prelude.appendFile fp ( Prelude.drop 0 tags )
where init = Prelude.appendFile fp "\ntagNameFromElem :: Element -> Group -> String\ntagNameFromElem e g\n"
tags = LS.concat $ Prelude.map (\tup -> " | " ++ (writeTup tup) ++ "\n") filTups
hexInt x = show . readHex $ x
filTups = LS.filter (\(w,x,y,z) -> Prelude.length w == 4 && Prelude.length x ==4 ) tups
This creates the desired function in Tags.hs
tagNameFromElem :: Int64 -> Int64 -> String
tagNameFromElem e g
| e == 8 && g == 1 = "LengthToEnd"
| e == 8 && g == 5 = "SpecificCharacterSet"
| e == 8 && g == 6 = "LanguageCodeSequence"
| e == 8 && g == 8 = "ImageType"
| e == 8 && g == 16 = "RecognitionCode"
| e == 8 && g == 18 = "InstanceCreationDate"
| e == 8 && g == 19 = "InstanceCreationTime"
| e == 8 && g == 20 = "InstanceCreatorUID"
| e == 8 && g == 22 = "SOPClassUID"
| e == 8 && g == 24 = "SOPInstanceUID"
| e == 8 && g == 26 = "RelatedGeneralSOPClassUID"
| e == 8 && g == 27 = "OriginalSpecializedSOPClassUID"
..... > 2000 more
Every so often there is a special case like
| e == 1000 && mod (g -5) 10 == 0 = "ShiftTableTriplet"
which put me off just using a map.
Now this approach works but it takes a very long time to load (Over a minute) the whole which makes me think that I'm not doing this how it should be done. To reproduce I suggest cloning the repo and loading the Tags.hs.
A SSCE
writeFunc :: (Num x, Show x) => FilePath -> [x] -> IO()
writeFunc fp xs = init >> Prelude.appendFile fp ( maps ) >> Prelude.appendFile fp "| otherwise = 0 "
where init = Prelude.appendFile fp "mapVal :: Int -> Int \nmapVal x\n "
maps = concat $ Prelude.map (\x -> "| x == " ++ show x ++ " = " ++ show (x +1 ) ++ "\n ") xs
Use a long list ~ few thousand values and try to import the resulting file
This answer is based on what bheklilr suggested in the question's comments. Code generation is up to you.
I reviewed your code and found that there are only two values in which e imposes special conditions on g: e == 28 and e == 1000. So, it'd be better to handle those in separate functions. Choose better names than the following ones, please.
e28 :: Map Int64 String
e28 = fromList [ (0, "CodeLabel"), (2, "NumberOfTables"), ... ]
e1000 :: Map Int64 String
e1000 :: fromList [ (0, "EscapeTriplet"), (1, "RunLengthTriplet"), ... ]
The keys of the previous maps are taken from your special-case predicate: mod (g - key) 10 == 0.
The case where e == 1010 is also special, since it doesn't depend on g. It's always "ZonalMap", so it'll be dealt with later.
Now, just create the rest of maps using g as key.
e40 :: Map Int64 String
e40 = fromList [ (2, "SamplesPerPixel"), (3, "SamplesPerPixelUsed"), ... ]
e84 :: Map Int64 String
e84 = fromList [ ... ]
...
Create a map from regular es (i.e. not the 28, 1000 or 1010 ones) to their corresponding map:
regularE :: Map Int64 (Map Int64 String)
regularE e = fromList [ (40, e40), (84, e84), ... ]
To sum it all up:
import Control.Monad
tagNameFromElem :: Int64 -> Int64 -> Maybe String
tagNameFromElem 28 g = lookup e28 (mod g 10)
tagNameFromElem 1000 g = lookup e1000 (mod g 10)
tagNameFromElem 1010 _ = Just "ZonalMap"
tagNameFromElem e g = lookup regularE e >>= (`lookup` g)
The lookup function is from Data.Map, just in case qualification is required. Using Maybe handles the case where e or g do not map to a valid tag name, instead of a hardcoded "Not Found" string.
Note that I haven't tested this code; I'm not at home right now.
If you want, try IntMap instead of Map. You'll need to work with regular Ints in this case, but it may be good for this project.
Related
Implement a function (myData2Fun) that takes a string as input and expands its compressed representation according to the rules for encoding series lengths. The essence of compression is that consecutive identical characters are combined into one group.For example:
1. Input: myData2Fun "C"
Output: [Single "C"]
2. Input: myData2Fun "cvvccf"
Output:[Single 'c',Multiple 'v' 2,Multiple 'c' 2,Single 'f']
It is also necessary to implement the data type required to solve the problem.
I am trying to solve the problem as follows:
data MyData2 = Multiple Char Integer | Single Char deriving(Show)
myData2Fun (h:t) = fff h t 1
fff x (h:t) acc
| h == x = fff x t (acc + 1)
| h /= x && acc > 1 = Multiple x acc : fff h t 1
| h /= x && acc == 1 = Single x : fff h t 1
fff x [] acc
| acc>0 = Multiple x acc : []
| acc == 0 = Single x : []
But my program is on a line with a single character, for example
Input: myData2Fun "c" returns Output: [Multiple 'c' 1],
instead of Output: [Single 'c']. Help me find the error and fix the code.
As #chepner hints you may use Data.List.group to simplify your job while keeping your MyData2 data type
import Data.Bool (bool) -- ternary operator
import Data.List (group)
f s = map (\g#(c:_) -> let n = length g
in bool (Single c) (Multiple c n) (n > 1)) (group s)
*Main> f "cvvccf"
[Single 'c',Multiple 'v' 2,Multiple 'c' 2,Single 'f']
So im doing this function and i need her to display on the screen the result of (premio ap x) , the problem is that (premio ap x)::Maybe Int , so its not a string.
joga :: Aposta -> IO ()
joga x= do
ap <- leAposta;
let arroz = (premio ap x)
putStr ^^^^^^^^^^
return ()
How can i convert this to a string? Or there is another way to display on the screen things that are not strings.
update :full code
comuns :: Aposta -> Aposta -> (Int,Int)
comuns (Ap a (b,c)) (Ap k (l,ç)) = (cnum a k, cnum [b,c] [l,ç])
cnum::[Int]->[Int]->Int
cnum [] l2 = 0
cnum (x:xs) l2 | elem x l2 = 1 + cnum xs l2
|otherwise = cnum xs l2
premio :: Aposta -> Aposta -> Maybe Int
premio l1 l2 | x == (5,2)= Just 1
| x == (5,1)= Just 2
| x == (5,0)= Just 3
| x == (4,2)= Just 4
| x == (4,1)= Just 5
| x == (4,0)= Just 6
| x == (3,2)= Just 7
| x == (2,2)= Just 8
| x == (3,1)= Just 9
| x == (3,0)= Just 10
| x == (1,2)= Just 11
| x == (2,1)= Just 12
| x == (2,0)= Just 13
|otherwise = Nothing
where
x = comuns l1 l2
leAposta :: IO Aposta
leAposta = do
putStrLn "Insira como lista as 5 estrelas"
num <-getLine
putStrLn "Insira em par as 2 estrelas"
es<-getLine
let ap = (Ap (read num) (read es))
if (valida ap)
then return ap
else do
putStrLn "Aposta invalida"
leAposta
Since arroz is premio ap x which has type Maybe Int, you can simply print arroz.
print works on any type that can be printed, i.e. on those types in class Show.
(You probably don't want to use print on values that are already strings, though, since that will print the escaped string, with quotes around. Use putStr and putStrLn for strings.)
I am working on a program to get the closest prime number by the exponent of 2, this is between an interval.
module Main where
import Data.Char
import System.IO
import Control.Monad (liftM)
data PGetal = G Bool | P Int
instance Show PGetal where
show (P n) = show n
show (G False) = "GEEN PRIEMGETAL GEVONDEN"
mPriem::(Int, Int) -> PGetal
mPriem (x,y) | (x > y) = G False
| (x > 1000000) = G False
| (y > 1000000) = G False
| (null (getAllPriem(x,y))) = G False
| otherwise = P (kleinsteVerschilF(getAllPriem(x,y),1000000,1))
kleinsteVerschilF:: ([Int], Int , Int) -> Int
kleinsteVerschilF ([],_, priemGetal) = priemGetal
kleinsteVerschilF (priem1:priemcss, kleinsteVerschil,priemGetal)=
if(kleinsteVerschil <= kleinsteVerschilMetLijst (priem1,(getMachtenVanTwee(0)),1000000))then kleinsteVerschilF(priemcss, kleinsteVerschil,priemGetal)
else kleinsteVerschilF (priemcss,kleinsteVerschilMetLijst(priem1,(getMachtenVanTwee(0)),1000000), priem1)
kleinsteVerschilMetLijst :: (Int,[Int],Int) -> Int
kleinsteVerschilMetLijst ( _,[],kleinsteVerschil) = kleinsteVerschil
kleinsteVerschilMetLijst (x,tweeMachten1:tweeMachtencss,kleinsteverschil)=
if((abs(x-tweeMachten1)) < kleinsteverschil)
then kleinsteVerschilMetLijst(x,tweeMachtencss, (abs(x-tweeMachten1)))
else kleinsteVerschilMetLijst(x,tweeMachtencss, kleinsteverschil)
getAllPriem :: (Int, Int) ->[Int]
getAllPriem (x,y) = filter isPriem [x..y]
getMachtenVanTwee ::(Int) -> [Int]
getMachtenVanTwee (macht)
|(functieMachtTwee(macht)< 1000000) = (functieMachtTwee(macht)) : (getMachtenVanTwee ((macht+1)))
| otherwise = []
functieMachtTwee:: (Int) -> Int
functieMachtTwee (x) = 2^x
isPriem n = (aantalDelers n)==2
aantalDelers n = telAantalDelersVanaf n 1
telAantalDelersVanaf n kandidaatDeler
| n == kandidaatDeler = 1
| mod n kandidaatDeler == 0
= 1 + telAantalDelersVanaf n (kandidaatDeler+1)
| otherwise
= telAantalDelersVanaf n (kandidaatDeler+1)
aantalDelers2 getal = telDelers getal 1 0
where telDelers n kandidaat teller
| n == kandidaat = 1+teller
| mod n kandidaat == 0
= telDelers n (kandidaat+1) (teller+1)
| otherwise
= telDelers n (kandidaat+1) teller
transform :: [String] -> [PGetal]
transform [] = []
transform (cs:css) =
let (a : b: _ ) = words cs
in (mPriem ((read(a)),(read(b))): transform css)
main :: IO ()
main = do
n <- read `liftM` getLine :: IO Int
lss <- lines `liftM` getContents
let cases = take n lss
let vs = (transform (lss))
putStr $ unlines $ map show vs
When I use the mPriem function, it works fine.
But it needs to work with an input txt file, so I made a .exe file with the ghc command. I also added this .txt file in the folder.
10
1 1
1 3
1 100
200 250
14 16
5 10
20 31
16 50
100 120
5200 7341
When I use in command line this command, it does nothing. There is no output. I can't CTRL+C to stop the program, so I think it crashes. But I don't know what's wrong.
type invoer.txt | programma.exe
Your program works, but is not that efficient and personally I find it not that elegant (sorry :S) because you introduce a lot of "noise". As a result it takes a lot of time before output is written.
If I understand the problem statement correctly, each line (except the first), contains two integers, and you need to count the amount of prime numbers between these two numbers (bounds inclusive?)
First of all, you can do this more elegantly by defining a function: cPrime :: Int -> Int -> Int that takes as input the two numbers and returns the amount of prime numbers:
cPrime :: Int -> Int -> Int
cPrime a b = count $ filter isPrime [a .. b]
You can improve performance by improving your prime checking algorithm. First of all, you do not need to check whether 1 is a divisor, since 1 is always a divisor. Furthermore, you can prove mathematically that there is no divisor greater than sqrt(n) (except for n) that divides n; unless there is another divider that is smaller than sqrt(n). So that means that you can simply enumerate all numbers between 2 and sqrt n and from the moment one of these is a divisor, you can stop: you have proven the number is not prime:
isPrime :: Int -> Bool
isPrime 1 = False
isPrime 2 = True
isPrime n = all ((0 /=) . mod n) (2:[3,5..m])
where m = floor $ sqrt $ fromIntegral n
Now I'm not sure what you aim to do with kleinsteVerschilF.
I'm writing a function like this:
testing :: [Int] -> [Int] -> [Int]
testing lst1 lst2 =
let t = [ r | (x,y) <- zip lst1 lst2, let r = if y == 0 && x == 2 then 2 else y ]
let t1 = [ w | (u,v) <- zip t (tail t), let w = if (u == 2) && (v == 0) then 2 else v]
head t : t1
What the first let does is: return a list like this: [2,0,0,0,1,0], from the second let and the following line, I want the output to be like this: [2,2,2,2,1,0]. But, it's not working and giving parse error!!
What am I doing wrong?
There are two kinds of lets: the "let/in" kind, which can appear anywhere an expression can, and the "let with no in" kind, which must appear in a comprehension or do block. Since your function definition isn't in either, its let's must use an in, for example:
testing :: [Int] -> [Int] -> [Int]
testing lst1 lst2 =
let t = [ r | (x,y) <- zip lst1 lst2, let r = if y == 0 && x == 2 then 2 else y ] in
let t1 = [ w | (u,v) <- zip t (tail t), let w = if (x == 2) && (y == 0) then 2 else y] in
return (head t : t1)
Alternately, since you can define multiple things in each let, you could consider:
testing :: [Int] -> [Int] -> [Int]
testing lst1 lst2 =
let t = [ r | (x,y) <- zip lst1 lst2, let r = if y == 0 && x == 2 then 2 else y ]
t1 = [ w | (u,v) <- zip t (tail t), let w = if (x == 2) && (y == 0) then 2 else y]
in return (head t : t1)
The code has other problems, but this should get you to the point where it parses, at least.
With an expression formed by a let-binding, you generally need
let bindings
in
expressions
(there are exceptions when monads are involved).
So, your code can be rewritten as follows (with simplification of r and w, which were not really necessary):
testing :: [Int] -> [Int] -> [Int]
testing lst1 lst2 =
let t = [ if y == 0 && x == 2 then 2 else y | (x,y) <- zip lst1 lst2]
t1 = [ if (v == 0) && (u == 2) then 2 else v | (u,v) <- zip t (tail t)]
in
head t : t1
(Note, I also switched u and v so that t1 and t has similar forms.
Now given a list like [2,0,0,0,1,0], it appears that your code is trying to replace 0 with 2 if the previous element is 2 (from the pattern of your code), so that eventually, the desired output is [2,2,2,2,1,0].
To achieve this, it is not enough to use two list comprehensions or any fixed number of comprehensions. You need to somehow apply this process recursively (again and again). So instead of only doing 2 steps, we can write out one step, (and apply it repeatedly). Taking your t1 = ... line, the one step function can be:
testing' lst =
let
t1 = [ if (u == 2) && (v == 0) then 2 else v | (u,v) <- zip lst (tail lst)]
in
head lst : t1
Now this gives:
*Main> testing' [2,0,0,0,1,0]
[2,2,0,0,1,0]
, as expected.
The rest of the job is to apply testing' as many times as necessary. Here applying it (length lst) times should suffice. So, we can first write a helper function to apply another function n times on a parameter, as follows:
apply_n 0 f x = x
apply_n n f x = f $ apply_n (n - 1) f x
This gives you what you expected:
*Main> apply_n (length [2,0,0,0,1,0]) testing' [2,0,0,0,1,0]
[2,2,2,2,1,0]
Of course, you can wrap the above in one function like:
testing'' lst = apply_n (length lst) testing' lst
and in the end:
*Main> testing'' [2,0,0,0,1,0]
[2,2,2,2,1,0]
NOTE: this is not the only way to do the filling, see the fill2 function in my answer to another question for an example of achieving the same thing using a finite state machine.
I am doing another Project Euler problem and I need to find when the result of these 3 lists is equal (we are given 40755 as the first time they are equal, I need to find the next:
hexag n = [ n*(2*n-1) | n <- [40755..]]
penta n = [ n*(3*n-1)/2 | n <- [40755..]]
trian n = [ n*(n+1)/2 | n <- [40755..]]
I tried adding in the other lists as predicates of the first list, but that didn't work:
hexag n = [ n*(2*n-1) | n <- [40755..], penta n == n, trian n == n]
I am stuck as to where to to go from here.
I tried graphing the function and even calculus but to no avail, so I must resort to a Haskell solution.
Your functions are weird. They get n and then ignore it?
You also have a confusion between function's inputs and outputs. The 40755th hexagonal number is 3321899295, not 40755.
If you really want a spoiler to the problem (but doesn't that miss the point?):
binarySearch :: Integral a => (a -> Bool) -> a -> a -> a
binarySearch func low high
| low == high = low
| func mid = search low mid
| otherwise = search (mid + 1) high
where
search = binarySearch func
mid = (low+high) `div` 2
infiniteBinarySearch :: Integral a => (a -> Bool) -> a
infiniteBinarySearch func =
binarySearch func ((lim+1) `div` 2) lim
where
lim = head . filter func . lims $ 0
lims x = x:lims (2*x+1)
inIncreasingSerie :: (Ord a, Integral i) => (i -> a) -> a -> Bool
inIncreasingSerie func val =
val == func (infiniteBinarySearch ((>= val) . func))
figureNum :: Integer -> Integer -> Integer
figureNum shape index = (index*((shape-2)*index+4-shape)) `div` 2
main :: IO ()
main =
print . head . filter r $ map (figureNum 6) [144..]
where
r x = inIncreasingSerie (figureNum 5) x && inIncreasingSerie (figureNum 3) x
Here's a simple, direct answer to exactly the question you gave:
*Main> take 1 $ filter (\(x,y,z) -> (x == y) && (y == z)) $ zip3 [1,2,3] [4,2,6] [8,2,9]
[(2,2,2)]
Of course, yairchu's answer might be more useful in actually solving the Euler question :)
There's at least a couple ways you can do this.
You could look at the first item, and compare the rest of the items to it:
Prelude> (\x -> all (== (head x)) $ tail x) [ [1,2,3], [1,2,3], [4,5,6] ]
False
Prelude> (\x -> all (== (head x)) $ tail x) [ [1,2,3], [1,2,3], [1,2,3] ]
True
Or you could make an explicitly recursive function similar to the previous:
-- test.hs
f [] = True
f (x:xs) = f' x xs where
f' orig (y:ys) = if orig == y then f' orig ys else False
f' _ [] = True
Prelude> :l test.hs
[1 of 1] Compiling Main ( test.hs, interpreted )
Ok, modules loaded: Main.
*Main> f [ [1,2,3], [1,2,3], [1,2,3] ]
True
*Main> f [ [1,2,3], [1,2,3], [4,5,6] ]
False
You could also do a takeWhile and compare the length of the returned list, but that would be neither efficient nor typically Haskell.
Oops, just saw that didn't answer your question at all. Marking this as CW in case anyone stumbles upon your question via Google.
The easiest way is to respecify your problem slightly
Rather than deal with three lists (note the removal of the superfluous n argument):
hexag = [ n*(2*n-1) | n <- [40755..]]
penta = [ n*(3*n-1)/2 | n <- [40755..]]
trian = [ n*(n+1)/2 | n <- [40755..]]
You could, for instance generate one list:
matches :: [Int]
matches = matches' 40755
matches' :: Int -> [Int]
matches' n
| hex == pen && pen == tri = n : matches (n + 1)
| otherwise = matches (n + 1) where
hex = n*(2*n-1)
pen = n*(3*n-1)/2
tri = n*(n+1)/2
Now, you could then try to optimize this for performance by noticing recurrences. For instance when computing the next match at (n + 1):
(n+1)*(n+2)/2 - n*(n+1)/2 = n + 1
so you could just add (n + 1) to the previous tri to obtain the new tri value.
Similar algebraic simplifications can be applied to the other two functions, and you can carry all of them in accumulating parameters to the function matches'.
That said, there are more efficient ways to tackle this problem.