【问题标题】:Using filter on an item in a list?对列表中的项目使用过滤器?
【发布时间】:2011-05-10 19:35:04
【问题描述】:

我正在尝试按列表中的项目过滤并逐行打印它们。这是我的代码:

data Car = Car String [String] Int [String]

testDatabase :: [Car]
testDatabase = [Car"Casino Royale" ["Daniel Craig"] 2006 ["Garry", "Dave", "Zoe", "Kevin", "Emma"],Car"Blade Runner" ["Harrison Ford", "Rutger Hauer"] 1982 ["Dave", "Zoe", "Amy", "Bill", "Ian", "Kevin", "Emma", "Sam", "Megan"]]



formatCarRow (Car a b c d) =  show a ++ " | " ++ concat [i ++ ", " | i <- init b] ++ last b ++ " | " ++ show c ++ " | " ++ concat [j ++ ", " | j <- init d] ++ last d



displayFilmsByYear :: String -> IO [()]
displayFilmsByYear chosenYear = mapM (putStrLn.formatFilmRow) [putStrLn(filter ((== chosenYear).y)) |  (w x y z) <- testDatabase] -- This is the code not working i think

为什么这不起作用?

【问题讨论】:

  • 您的意思是data Film = Car …?否则testDatabase 中存在类型不匹配。 formatFilmRow / formatCarRow 类似。
  • 我现在编辑了这个,抱歉这不是问题原来的问题仍然存在:/
  • 只是出于好奇:您是否使用随机生成器来决定单词 putStrLn 在程序文本中的位置?开个玩笑.... :)
  • 请考虑将您的程序分成许多较小的函数。这样你就可以思考得更清楚了。尽管这里的具体问题是其他问题,但一旦您整理了代码,错误就会出现。

标签: list haskell filter


【解决方案1】:

如果你想过滤一个列表,我推荐使用filter 函数:)

data Car = Car String [String] Int [String]

year :: Car -> Int
year (Car _ _ y _) = y

filterByYear :: Int -> [Car] -> [Car]
filterByYear chosenYear cars = filter (\car -> year car == chosenYear) cars

showCar :: Car -> String
showCar car = undefined -- you can implement this how you like

displayCarsByYear :: Int -> IO ()
displayCarsByYear chosenYear = mapM_ (putStrLn . showCar) filteredCars
    where filteredCars = filterByYear chosenYear testDatabase

在这里解释几件事似乎是明智的:

匿名函数(\car -&gt; year car == chosenYear) 是一个匿名函数。它接受一个参数并将其称为car。然后它确定该车的年份是否等于chosenYear。我没有明确写这个函数的类型签名,但它是Car -&gt; Bool

过滤:我把这个函数交给filter,这样它就可以查看Cars 的列表。当filter 找到该函数返回True 的汽车时,它会将它们放入结果列表中。 False 结果意味着汽车没有通过过滤器。

函数组合(putStrLn . showCar)这是一个先执行showCar,然后在showCar的结果上使用putStrLn的函数。

在哪里:您会注意到我的代码末尾的 where 语句。它应该是不言自明的,您可以使用letwhere 语句来定义“局部变量”。就口味而言,我更喜欢 where 而不是 let。

列表解析与过滤器:列表解析可以像过滤器功能一样过滤列表。对于函数f :: a -&gt; Bool 和列表xs :: [a]

filter f xs[x | x &lt;- xs, f x] 相同。出于个人喜好,在这种情况下,我更喜欢拼写 filter,因为这样可以清楚地表明我正在过滤列表。

另见LYAH # Maps and filters

--

进一步推荐:使用记录语法

代替

data Car = Car String [String] Int [String]

为什么不

data Film = Film { name :: String
                 , actors :: [String]
                 , released :: Int
                 , characters :: [String]
                 }

(我真的不知道你最后的字符串列表是什么)

这样,你可以像这样构造一个电影:

lotr :: Film
lotr = Film { name = "Lord of the Rings"
            , actors = ["Elijah Wood", "Ian McKellen", "Orlando Bloom"]
            , released = 2001
            , characters = ["Frodo", "Sam", "Pippin", "Merry"]
            }

而且你自动拥有访问函数

  • released :: Film -&gt; Int
  • name :: Film -&gt; String
  • 等等

另见LYAH # Record syntax

【讨论】:

  • Haskell / 教学天才 - 你不知道你刚刚教了我多少帮助、多少意义和多少。非常感谢!
【解决方案2】:

重点是:

[putStrLn(filter ((== chosenYear).y)) |  (w x y z) <- testDatabase]

你还没有理解列表理解。 你想要的是:

[ (Car w x y z) | (Car w x y z) <- testDatabase, y==choosenYear]

大概吧。

 mapM (putStrLn . formatCarRow) 

您已经订购了:格式化并打印以下列表中的每个元素。因此,列表推导式中的 putStrLn 是完全荒谬的。

请注意 putStrLn 在某种程度上是用词不当:它实际上不会打印任何东西!它只是构造了一个在 IO monad 中执行时会导致打印的东西。这似乎很难理解,但很快你就会明白了。

【讨论】:

  • @Ingo:感谢您的回复(对上面的评论大声笑,这是另一项工作,所以我不得不更改变量名:/)这是我现在得到的错误:-输入错误生成器 *** 术语:(w,x,y,z) *** 类型:(a,b,c,d) *** 不匹配:电影
  • 查看我的更正。我错过了你有一个数据构造函数。 (昨天不是元组吗?)
  • 这是一个元组,但我将其更改为“数据”而不是“类型”,我必须做的其他功能的代码似乎少了很多,我很难理解我想要做的就是您在上面所做的,但调用“formatCarRow”以特定方式格式化行以进行打印 - 我必须以与此类似的方式进行操作,无需额外的库为我做: /
  • 用 formatCarRow 替换 formatFilmRow 有什么问题?如果我能给你一个建议:不要一次做所有事情(格式化、处理项目列表、做 IO)。开始编写 formatCarRow 或任何你叫它的东西,它接受一个 Car 并返回(不是:打印!!!)一个字符串。在 ghci 中测试这个功能。如果您对结果满意,请回过头来提出问题:我有一个函数 Car -> String,如何打印汽车列表。
  • 好吧,我会试试,我是这个的初学者,我如何让它返回一个字符串,我以为它已经是了?
猜你喜欢
  • 1970-01-01
  • 2020-07-08
  • 1970-01-01
  • 2011-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
相关资源
最近更新 更多