filter1 :: (a -> Bool) -> [a] -> [a]
filter1 p = concat.map box
where box x
| p x = [x]
| otherwise = []
我不明白这个解决方案。 map将box应用于列表的所有元素,如果p x == True它将元素放在单个元素的列表中,然后连接取消所有内容? concat最终将所有内容统一起来或逐一统一?
谢谢!我希望有人理解这个
答案 0 :(得分:6)
很难从你的问题中辨别出你的实际要求。请尝试清楚地表达您的问题。我将解释这个函数是如何工作的,并希望这个解释可以解决你实际要求的任何问题。
首先,map box
应用于输入列表。对box
的每次调用都会返回[x]
,对于那些满足谓词x
的{{1}};或者一个空列表,用于那些不满足谓词的p
。因此,x
的结果将是空列表和单例列表的列表。
让我们考虑一个例子。我们这样说:
map box
然后:
input_list = [1,2,3,4,5]
p = odd
第一个元素map box input_list = [ [1], [], [3], [], [5] ]
已映射到1
,因为[1]
。第二个元素p 1 == True
已映射到2
,因为[]
。等等。
之后,p 2 == False
将应用于此列表列表。它将所有这些小清单连接成一个大清单。所以在我们的例子中:
concat
答案 1 :(得分:2)
想象一下,我们有五个要素:
[x1, x2, x3, x4, x5]
并且p
适用于x2
,x3
和x5
。然后我们按如下方式执行映射:
map box [x1, x2, x3, x4, x5]
------------------------------------------
= [box x1, box x2, box x3, box x4, box x5]
由于p
适用于x2
,x3
和x5
,这意味着box
会返回x1
和{{}的空列表1}},以及包含x4
,x2
和x3
原始列表的单例列表,所以:
x5
然后,如果我们应用 [box x1, box x2, box x3, box x4, box x5]
------------------------------------------
= [[], [x2], [x3], [], [x5]]
,则空列表(concat
)将不会向结果中添加任何元素,因此原始元素被"过滤掉",而单身人士名单的内容 - []
所持有的元素 - 被添加到列表中,因此:
p
因此,通过将我们想要过滤的元素映射到空列表,以及我们想要保留到具有该元素的单例列表的元素,并连接这些元素,我们设法过滤掉我们不想要的元素。然而,对于过滤来说,如果没有优化,则效率不高,因为我们将所有想要的元素装箱和拆箱。
请注意,Haskell是一种惰性语言,所以如果你以某种方式 concat [[], [x2], [x3], [], [x5]]
-----------------------------------
= [x2, x3, x5]
某些元素,那么这是不执行,除非你需要结果。此外,filter1
和map
都是懒惰的(就像所有函数一样)。这意味着如果我们对结果的 i -th元素感兴趣,我们将不会计算整个列表。