我一直在与Haskell玩,并编写一些代码来解析DICOM医学图像。代码在这里。我想创建一个将接受ByteString并返回名称的函数。因此,某个ByteString(实际上是从ByteString中获取的两个Int64)将返回PatientName或StudyDate。其中有成千上万个,它们都包含在XML文件中。因此,为了创建函数,我将解析XML文件并生成所需的函数,然后使用以下命令将其输出到文件中
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
这将在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
每隔一段时间就有一个特殊情况
| e == 1000 && mod (g -5) 10 == 0 = "ShiftTableTriplet"
这使我不仅仅使用地图。
现在,这种方法可以工作,但是要花很长时间(超过一分钟)来加载整个过程,这使我认为我没有做到这一点。为了重现,我建议克隆存储库并加载Tags.hs。
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
使用很长的列表〜几千个值,然后尝试导入结果文件
该答案基于问题的评论中bheklilr的建议。代码生成取决于您。
我查看了您的代码,发现仅存在其中两个值e
规定了特殊条件g
:e == 28
和e == 1000
。因此,最好在单独的函数中处理它们。请选择比以下名称更好的名称。
e28 :: Map Int64 String
e28 = fromList [ (0, "CodeLabel"), (2, "NumberOfTables"), ... ]
e1000 :: Map Int64 String
e1000 :: fromList [ (0, "EscapeTriplet"), (1, "RunLengthTriplet"), ... ]
先前地图的键来自特殊情况的谓词:mod (g - key) 10 == 0
。
这里的情况e == 1010
也很特殊,因为它不依赖g
。它始终是“ ZonalMap”,因此将在以后处理。
现在,只需使用g
键创建其余的地图。
e40 :: Map Int64 String
e40 = fromList [ (2, "SamplesPerPixel"), (3, "SamplesPerPixelUsed"), ... ]
e84 :: Map Int64 String
e84 = fromList [ ... ]
...
从常规e
s(即不是28、1000或1010的)创建一个映射到其对应的映射:
regularE :: Map Int64 (Map Int64 String)
regularE e = fromList [ (40, e40), (84, e84), ... ]
总结一下:
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)
该lookup
函数来自Data.Map,以防万一需要限定条件。使用会Maybe
处理以下情况:映射到e
或未g
映射到有效标签名的情况,而不是映射到硬编码的“未找到”字符串的情况。
请注意,我尚未测试此代码。我现在不在家
如果需要,请尝试IntMap
代替Map
。Int
在这种情况下,您需要使用Regular ,但是这对本项目可能是好的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句