因此,我有两个文件,其内容如下:
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现在,我认为一切都是正确的,除了返回IO()而不是字符串的解析函数之外,我如何更改它?
发布于 2013-12-11 15:35:37
好的,首先我不明白函数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。然而,如果这是家庭作业,可能不在练习的范围之内。
为了序列化..。我认为,一旦你做了你需要做的,在那里添加所有的空格-记住,名字和数字之间的空格和数字后面的换行符,你会没事的。
https://stackoverflow.com/questions/20519572
复制相似问题