我一直在玩Haskell并编写一些代码来解析DICOM医学图像。代码是here。我想创建一个将接收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"
让我只使用地图。
现在这种方法有效但是需要很长时间才能加载(超过一分钟)整体,这让我觉得我没有这样做,应该怎么做。为了重现我建议克隆repo并加载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
使用长列表〜几千个值并尝试导入生成的文件
答案 0 :(得分:2)
这个答案是基于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
(即不是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
,但这对此项目可能有用。