在Haskell制作电话簿
我有两个文件,内容如下:在Haskell制作电话簿,haskell,io,monads,Haskell,Io,Monads,我有两个文件,内容如下: File 1: Tom 965432145 Bill 932121234 File 2: Steve 923432323 Tom 933232323 我想合并它们,并将结果输出写入一个名为“out.txt”的文件。我编写这个函数是为了处理重复项(当同一个名称多次出现时,它会选择进入最终文件的数字) 该函数称为选择: choosing :: [String] −> Int −> Int −> Int choosing ("Na
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
以下是我迄今为止根据tips所做的工作:
我把问题分解成小函数,这样更容易解决
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
import Text.Printf
导入文本.Parsec
导入Text.Parsec.String
选择um1 num2
|num2`div`100000000==2=num2
|否则=num1
parseNameNumber::解析器(字符串,整数)
parseNameNumber=do
空间
姓名打印资源
快速排序::Ord a=>[a]->[a]
快速排序[]=[]
快速排序(p:xs)=(较小的快速排序)+[p]+(较大的快速排序)
哪里
较小=过滤器(=p)xs
合并条目::[(字符串,Int)]->[(字符串,Int)]->[(字符串,Int)]
合并条目[]y=y
合并条目x[]=x
合并条目xl@(x@(xname,xphone):xs)yl@(y@(yname,yphone):ys)
|xnameyname=y:mergeEntries xs yl
序列化条目::[(Int,Char)]->[Char]
serializeEntries=concatMap(uncurry$printf“%s%d\n”)项
main=do
entries1好的,首先我不理解选择的功能。你能用简单的英语解释一下它是如何选择数字的吗?我这样问是因为你们有两个相互矛盾的定义。你的第一个定义是:
choosing :: [String] −> Int −> Int −> Int
choosing ("Name_of_person":_) num1 _ = num1
choosing _ num1 num2
| num2 ‘div‘ 100000000 == 2 = num2
| otherwise = num1
英语中的意思是“如果人名以字面字符串name\u of_person
开头,请始终选择第一个数字。否则,如果第二个数字在200000000…29999999范围内,请选择第二个数字;如果不是,请选择第一个数字”。那是。。。奇怪,但也许有一个很好的理由
但是,当您布置整个模块时,您不会这样做。在这里,您有两个完整的选择
,实际上是说“始终选择第一个数字”,因为第一个模式(选择名称num1
)总是匹配的
因此,首先,找出您想用选择
做什么。我怀疑你想做的是注释掉第一个定义
现在,关于合并。文件是否按人名排序?不然后,您需要在读取列表后对其进行排序,以便识别两个文件之间何时存在匹配的名称。列表排序后,您必须进行排序合并:
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
mergeEntries[]y=y
合并条目x[]=x
合并条目xl@(x@(xname,xphone):xs)yl@(y@(yname,yphone):ys)
|xnameyname=--您填写这部分
或者,您可以使用比列表更好的数据结构(如Map
)来代替排序,并使用fromListWith
和toList
。但是,如果这是作业,则可能不在练习参数范围内
用于序列化。。。我想,一旦你做了你需要做的事情,把所有的空格都加进去,你就会没事的。记住,名字和数字之间有一个空格,数字后面有一个换行符。很抱歉给你带来不便@BartekBanachewicz,我已经改了:)对不起,是的,选择的第一行应该被省略,当不同文件中有相同名称的条目时,只需选择一个数字。这是mergeEntries的正确实现吗?需要完成什么|xname==yname=选择xname x y:mergeEntries xs yl
|xname>yname=y:mergeEntries xs yl
关闭,但您需要:|xname==yname=选择xname xphone ypphone:mergeEntries xs ys
,然后还要选择|xname>yname=y:mergeEntries xl ys
。xl
和yl
与xs
和ys
变量之间的差异是显著的,值得仔细考虑。