所以我有两个文件包含以下内容:
File 1:
Tom 965432145
Bill 932121234
File 2:
Steve 923432323
Tom 933232323
我想合并它们并将结果输出写入名为'out.txt'的文件。我写了这个函数来处理重复项(当同一个名字出现不止一次时,它会选择最终文件中的数字)。
该函数调用选择:
choosing :: [String] −> Int −> Int −> Int
choosing ("Name_of_person":_) num1 _ = num1
choosing _ num1 num2
| num2 ‘div‘ 100000000 == 2 = num2
| otherwise = num1
这是我到目前为止根据提示设法做的事情:
我将问题分解为小函数,因此解决它会更容易。
import Text.Printf
import Text.Parsec
import Text.Parsec.String
choosing _ num1 num2
| num2 `div` 100000000 == 2 = num2
| otherwise = num1
parseNameNumber :: Parser (String, Integer)
parseNameNumber = do
spaces
name <- many1 letter
space
number <- fmap read $ many1 digit
return (name, number)
parseFile :: String -> IO ()
parseFile = do
result <- parseFromFile (parseNameNumber `sepBy` newline)
case result of
Left err -> print err
Right res -> print res
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
where
lesser = filter (< p) xs
greater = filter (>= p) xs
mergeEntries :: [(String, Int)] -> [(String, Int)] -> [(String, Int)]
mergeEntries [] y = y
mergeEntries x [] = x
mergeEntries xl@(x@(xname, xphone):xs) yl@(y@(yname, yphone):ys)
| xname < yname = x : mergeEntries xs yl
| xname == yname = choosing xname x y : mergeEntries xs yl
| xname > yname = y : mergeEntries xs yl
serializeEntries :: [(Int, Char)] -> [Char]
serializeEntries entries = concatMap (uncurry $ printf "%s %d\n") entries
main = do
entries1 <- fmap parseFile $ readFile "in1.txt"
entries2 <- fmap parseFile $ readFile "in2.txt"
writeFile "out.txt" $ serializeEntries $ mergeEntries $ quicksort entries1 quicksort entries2
现在我认为一切都是正确的,除了我的parse函数返回IO()而不是字符串,我该如何改变呢?
答案 0 :(得分:0)
好的,首先我不理解函数choosing
。你能用简单的英语解释它如何选择数字吗?我问,因为那里有两个相互矛盾的定义。您所说的第一个定义是:
choosing :: [String] −> Int −> Int −> Int
choosing ("Name_of_person":_) num1 _ = num1
choosing _ num1 num2
| num2 ‘div‘ 100000000 == 2 = num2
| otherwise = num1
这句用英语说的是“如果这个人的姓名以文字字符串Name_of_person
开头,请始终选择第一个数字。否则,如果第二个数字在200000000 ... 299999999范围内,请选择第二个数字;如果不是,请选择第一个数字“。那是......很奇怪,但也许有充分的理由。
但是,当您放置整个模块时,不会这样做。在那里,你拥有的是choosing
的两个完整定义,并且实际上是在说“总是选择第一个数字”,因为第一个模式(choosing name num1 _
)总是匹配。
首先,弄清楚你想对choosing
做些什么。我怀疑你想要做的是评论第一个定义。
现在,至于合并。文件是按人名排序的吗?没有?然后,您需要在读取列表后对列表进行排序,以便识别两个文件之间是否存在匹配的名称。列表排序后,您将不得不进行排序合并:
mergeEntries [] y = y
mergeEntries x [] = x
mergeEntries xl@(x@(xname, xphone):xs) yl@(y@(yname, yphone):ys)
| xname < yname = x : mergeEntries xs yl
| xname == yname = -- You fill in this part, using choosing here
| xname > yname = -- You fill in this part
或者,除了排序之外,您可以使用比列表更好的数据结构(例如Map
)并使用fromListWith
和toList
。但是,如果这是家庭作业,可能不在练习的参数范围内。
对于序列化...我认为一旦你做了你需要做的事情就可以添加所有空格 - 请记住,名称和数字之间的空格以及数字后面的换行符。