简体   繁体   English

在Haskell的列表列表中过滤元素

[英]Filter for element in a list of lists in Haskell

I built a list of this structure: 我建立了这个结构的清单:

[(Interger, Double)]

The List was created by using a zip over a list of Integers and a list of Doubles of exactly the same size. 该列表是通过在整数列表和大小完全相同的Doubles列表上使用zip来创建的。

Now I want to filter the list for Doubles that are either <18.5 or >25. 现在,我要过滤<18.5或> 25的双打列表。 The problem I have is I can't access the Doubles to use them in the filter function. 我的问题是我无法访问Doubles在过滤器功能中使用它们。

It's probably easy but I'm a bloody noob in this language. 这可能很简单,但是我是这种语言中的流氓。 I googled around a lot and read some other threads but I didn't find an answer. 我在Google上搜索了很多,还读了其他一些主题,但没有找到答案。

I got: 我有:

filter (<18.5) listexpression

So what I'm struggling with is that listexpression. 所以我正在努力的是listexpression。 It's easy if it's a list of single values. 如果它是单个值的列表,这很容易。 I could filter before zipping but then I can't connect the data from the filtered list to the other unfiltered List anymore. 我可以在压缩之前进行过滤,但是之后我无法再将数据从过滤列表连接到另一个未过滤列表。

Edit: I forgot to mention. 编辑:我忘了提。 It's a worksheet. 这是一个工作表。 We were asked to build filter and map functions ourselves and are not allowed to use any additions to the basic Haskell. 我们被要求自己构建过滤器和映射函数,并且不允许对基本的Haskell使用任何附加功能。 Meaning no imports are allowed. 表示不允许进口。

You can do something like this: 您可以执行以下操作:

Prelude> filter (\p -> (snd p) < 18.5 || (snd p) > 25) [(1, 2.3), (1, 20.0)]
[(1,2.3)]

The lambda function passed to filter , namely 传递给filterlambda函数 ,即

(\p -> (snd p) < 18.5 || (snd p) > 25)

says that for every p , the second element of p must be less than 18.5 or over 25. 说,对于每个p ,的第二个元素p必须小于18.5或超过25。


Alternatively, you could write it like this 或者,您可以这样写

Prelude> filter (\(_, f) -> f < 18.5 || f > 25) [(1, 2.3), (1, 20.0)]
[(1,2.3)]

Here the function says that for any pair whose first value doesn't matter and the second one is f , f must be less than 18.5 or over 25. 这里的函数说,对于第一个值无关紧要而第二个值是f任何一对, f必须小于18.5或大于25。

Glad to see Ami Tavory's answer solved your problem. 很高兴看到Ami Tavory的答案解决了您的问题。

But under that answer, you commented: 但是在该答案下,您评论了:

I tried accessing it with a combination of (!!) but that didn't work. 我尝试使用(!!)的组合来访问它,但是没有用。

With the insight of a teaching assistant [:D], I guess you confused list with tuple in Haskell. 凭着助教[:D]的见识,我想您将list与Haskell中的tuple混淆了。

zip returns a list of tuple , whereas (!!) take a list as (the first) argument (hence (!!1) take a single list argument), so (!!1) can't be applied to elements of the list returned by zip , which are of type tuple . zip返回一个tuple list ,而(!!)list作为(第一个)参数(因此(!!1)采用单个list参数),因此(!!1)不能应用于zip返回的list ,其类型为tuple

Prelude> :t zip
zip :: [a] -> [b] -> [(a, b)]
Prelude> :t (!!)
(!!) :: [a] -> Int -> a
Prelude> :t (!!1)
(!!1) :: [a] -> a

And you've known that fst and snd are applied to tuple . 并且您已经知道fstsnd应用于tuple

Prelude> :t fst
fst :: (a, b) -> a
Prelude> :t snd
snd :: (a, b) -> b

A compact version using point free style would be 使用无点样式的紧凑版本将是

 filter ((>18.5).snd) listexpression

This uses the function composition operator . 这使用函数组合运算符. , which reads as: First apply the snd function to a tuple from the list to extract the 2nd value, then apply the comparison to 18.5 to this value. ,其内容为:首先将snd函数应用于列表中的元组以提取第二个值,然后将比较值18.5应用于此值。

Just for a variety and some additional information which won't bite... 只是为了提供各种内容和一些其他信息,这些信息将不会咬人。

In Haskell the list type is an instance of Monad class . 在Haskell中,列表类型是Monad类的实例 So a list operation like filter can simply be implemented by a monadic bind operator. 因此,列表操作(例如filter可以简单地由monadic bind操作符实现。

*Main> [(1,2.3),(3,21.2),(5,17.1),(4,24.4)] >>= \t -> if snd t < 25 && snd t > 18.5 then [t] else []
[(3,21.2),(4,24.4)]

Monad is all about handling the contained data in a sequential manner. Monad就是以顺序方式处理包含的数据。 In the list monad the contained data is the value within the list itself. 在列表monad中,包含的数据是列表本身内的值。 So the bind operator can be very handy to access to contained values (tuples) of the monadic value (the list of tuples) in a sequential manner. 因此,bind运算符可以非常方便地按顺序访问单子值(元组列表)的包含值(元组)。

(>>=) :: Monad m => m a -> (a -> m b) -> m b

The type signature of the monadic bind operator states that it takes a monad type value ma as the first argument (the list of tuples here) and a function as the second argument which takes a pure value and returns a monadic value (takes a tuple and returns a tuple in a list or an empty list in this case). monadic绑定运算符的类型签名指出,它将monad类型值ma作为第一个参数(此处为元组列表),将函数用作第二个参数,该函数采用纯值并返回monadic值(采用元组和返回列表中的元组或在这种情况下返回空列表)。

\t -> if snd t < 25 && snd t > 18.5 then [t] else []

It's critical to understand how and why the list items are applied one by one to the provided function. 了解如何以及为什么将列表项一一应用于所提供的功能至关重要。 An entire list is one monadic value and the contained values those accessed by the bind operator are passed to the provided a -> mb (take a pure value and return monadic value) type function. 整个列表是一个Monadic值,绑定操作符访问的包含值将传递给提供a -> mb (采用纯值并返回Monadic值)类型的函数。 So all of the list items those applied to this function become a monadic value ( [t] if condition satisfies or [] if it fails), are then concatenated by the bind operator to form one monadic return value (in this case a list of tuples those satisfy the condition which is implemented in the lambda function). 因此,所有应用于此函数的列表项都变为单子值(如果条件满足,则为[t]如果条件失败,则为[] ),然后由bind运算符连接起来以形成一个单子返回值(在这种情况下,列表为满足lambda函数中实现的条件的元组)。

This monadic operation can also be implemented with the do notation 此monadic操作也可以使用do表示法实现

do
t <- [(1,2.3),(3,21.2),(5,17.1),(4,24.4)]
if snd t < 25 && snd t > 18.5 then return t else []

[(3,21.2),(4,24.4)]

Of course this terribly resembles the list comprehensions which is in fact a syntactical sugar to the monadic list operations. 当然,这完全类似于列表理解,实际上是单子列表操作的语法糖。 So lets implement it for a final time by using the list comprehensions. 因此,让我们使用列表推导在最后一次实现它。

*Main> [t | t <- [(1,2.3),(3,21.2),(5,17.1),(4,24.4)], snd t < 25 && snd t > 18.5]
[(3,21.2),(4,24.4)]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM