所以,例如,假设我有一个数字列表,我想创建一个列表,其中包含每个数字乘以2和3.有没有办法做类似下面的事情,但得到一个单一的列表数字而不是数字列表列表?
mult_nums = [ [(n*2),(n*3)] | n <- [1..5]]
-- this returns [[2,3],[4,6],[6,9],[8,12],[10,15]]
-- but we want [2,3,4,6,6,9,8,12,10,15]
答案 0 :(得分:17)
我发现扩展列表理解使这更容易阅读:
[ m | n <- [1..5], m <- [2*n,3*n] ]
确切地检查它的作用以及它与其他解决方案的关系可能会有所帮助。让我们将其定义为一个函数:
mult lst = [ m | n <- lst, m <- [2*n,3*n] ]
经过时尚,这desugars到
mult' lst =
concatMap (\n -> concatMap (\m -> [m]) [2*n,3*n]) lst
表达式concatMap (\m -> [m])
将m
包裹在列表中,以便立即展平它 - 它等同于map id
。
将此与@ FunctorSalad的答案进行比较:
mult1 lst = concatMap (\n -> [n*2,n*3]) lst
我们已经优化了concatMap (\m -> [m])
。
现在@vili的回答:
mult2 lst = concat [ [(n*2),(n*3)] | n <- lst]
这令人厌恶:
mult2' lst = concat (concatMap (\n -> [[2*n,3*n]]) lst)
与上面的第一个解决方案一样,我们不必要地创建了concat
之外的列表列表。
我认为没有一种解决方案可以使用列表推导,但是可以使用mult1
。我的直觉是Haskell编译器通常足够聪明,这无关紧要(或者,由于懒惰的评估,不必要的concat
便宜(而在急切的语言中它们是致命的))。
答案 1 :(得分:13)
你可以使用concat。
concat [ [(n*2),(n*3)] | n <- [1..5]]
output: [2,3,4,6,6,9,8,12,10,15]
答案 2 :(得分:5)
在某些类似的情况下,concatMap也很方便,不过这里变化不大:
concatMap (\n -> [n*2,n*3]) [1..5]