我有一个文件(points.txt)定义了一些笛卡尔坐标:
A 1.0 2.2
B 2.1 3.0
C 3.5 4.0
D 4.0 5.0
Run Code Online (Sandbox Code Playgroud)
我有第二个文件(routes.txt),其路由根据points.txt中的点定义.
route1 ACDB
route2 ABC
Run Code Online (Sandbox Code Playgroud)
我需要找到每条路线的长度.到目前为止,我计算了两点之间的距离,如下所示:
type Point = (String, Float, Float)
distance_points :: IO ()
distance_points = do s <- readFile "pontos.txt"
putStr "Fom: "
p1 <- getLine
putStr "To: "
p2 <- getLine
print ( distance (search_point p1 (map words (lines s))) (search_point p2 (map words (lines s))))
search_point :: String -> [[String]] -> Point
search_point pt ([p,c1,c2]:xs) = if pt == p then (p, read(c1)::Float, read(c2)::Float)
else search_point pt xs
distance :: Point -> Point -> Float
distance (s1,x1,y1) (s2,x2,y2) = sqrt ((x1-x2)^2 + (y1-y2)^2)
Run Code Online (Sandbox Code Playgroud)
如何计算路线的全程?
另外,如果我有几条路线,我怎样才能找到最长的路线?
提前致谢.
最简单的方法是先用纯代码解决问题,然后再添加文件读取.否则你会想要编写很多IO代码.
如果将名称与坐标分开,会更容易:
type Coordinates = (Float,Float)
type Name = Char -- You had String, which is also fine
type Point = (Name, Coordinates)
type Points = [Point] -- or Map String Point from Data.Map
Run Code Online (Sandbox Code Playgroud)
然后有一些练习数据:
sampleData :: Points
sampleData = [('A',(1.0,2.2), .....
Run Code Online (Sandbox Code Playgroud)
首先,你需要一个带名字的函数并给你一些坐标.
coordinates :: Points -> Name -> Coordinates
Run Code Online (Sandbox Code Playgroud)
如果我们正在使用[Point],最简单的方法是使用lookup.(你可以找到关于hoogle功能这样或类型这样的,虽然有让你知道你想要一个没有明显的方式Maybe,当你只是搜索[(a,b)] -> b,查找是一个很长的路了.)
如果您需要此步骤的帮助,请发表评论.
使用它你就可以写
distBetween :: Points -> Name -> Name -> Float
Run Code Online (Sandbox Code Playgroud)
getPath :: String -> [(Name,Name)]
Run Code Online (Sandbox Code Playgroud)
或(冷却器)zipWith用来到达距离.之后,申请sum应该很容易完成问题.
制作这个对列表的很酷的方法是使用我们用于fibs = 0 : 1 : zipWith (+) fibs (tail fibs)使用其尾部压缩函数的fibonacci数字()的技巧.如果你没有遇到它,zip就像这样:
ghci> zip [1..5] "Hello Mum"
[(1,'H'),(2,'e'),(3,'l'),(4,'l'),(5,'o')]
zip "Hello" "ello"
[('H','e'),('e','l'),('l','l'),('l','o')]
*Main> zip "Hello" (tail "Hello")
[('H','e'),('e','l'),('l','l'),('l','o')]
Run Code Online (Sandbox Code Playgroud)
太棒了 - 这正是你需要的技巧.
你需要像这样的功能
readPointsFile :: FilePath -> IO Points
readPointsFile fileName = do
....
....
return (map readPoint pointStrings)
Run Code Online (Sandbox Code Playgroud)
然后你可以将它粘在一起,例如:
pathLengthFile :: FilePath -> FilePath -> IO Float
pathLengthFile pointsFilename pathFilename = do
points <- readPointsFile pointsFilename
path <- readPathFile pathFilename
return (getPathLength points path)
Run Code Online (Sandbox Code Playgroud)
注意这个位中几乎没有任何逻辑.你可以用纯粹的代码完成所有真正的移植.
偷偷地说,我是一个巨大的Applicative粉丝,并希望import Control.Applicative并将其写成
pathLengthFile pointsFile pathFile =
getPathLength <$> readPointsFile pointsFile <*> readPathFile pathFile
Run Code Online (Sandbox Code Playgroud)
但这是后来的另一个教训.:)