尝试将列表中大于5的元素加倍。
将列表中的每个元素加倍,我会这样做
doubleAll n = [2*x| x <-n]
现在我想使用列表推导将列表中所有大于5的元素加倍。 所以,如果我这样做
doubleAll n = [2*x| x <-n, x>5]
我的清单[1,2,3,4,5]会导致[10]。但我希望我的清单显示[1,2,3,4,10]
任何人都可以解释我做错了什么以及如何解决这个问题?
答案 0 :(得分:2)
对[2*x| x <-n, x>5]
的解释是:
n
获取下一个元素并将其命名为x
x>5
继续,否则转到第1步2*x
作为列表的下一个元素。很明显,x>5
过滤了n
的元素。表达式相当于:
map (\x -> 2*x) ( filter (\x -> x>5) n )
如Arthur所述,您需要以下内容:
[ if x > 5 then 2*x else x | x <- n ]
它的解释是:
n
的下一个值,并将其命名为x
if x > 5 then 2*x else x
作为列表的下一个值。答案 1 :(得分:0)
如果您不使用列表推导并使用map
和filter
操作,则可以更清楚地理解:
-- Apply a function to every element of the list.
map :: (a -> b) -> [a] -> [b]
-- Throw out list elements that don't pass the test.
filter :: (a -> Bool) -> [a] -> [a]
您的原始doubleAll
与此相同:
-- Multiply every element of the list by two.
doubleAll xs = map (*2) xs
仅当x > 5
为此时才加倍的版本:
-- Apply the `step` function to every element of the list. This step function
-- multiplies by two if x >= 5, otherwise it just returns its argument.
doubleAll xs = map step xs
where step x | x >= 5 = 2*x
| otherwise = x
您编写的列表推导版本的问题是它等同于此:
-- Filter out list elements that are smaller than 5, then double the remaining ones.
doubleAll xs = map (*2) (filter (>=5) xs)
产生所需结果的列表推导解决方案将改为:
doubleAll xs = [if x >= 5 then x*2 else x | x <- xs]
作为一个更一般的评论,我总是建议新手远离列表理解并学习更高阶列表功能,这些功能更通用,更不神奇。