假设我有一个这样的列表
let a =[["Warning:","Route","1543","must","Stop","on","Link","11881"],["Warning:","Route","1578","must","Stop","on","Link","12171"]]
我想提取其中每个列表的第三个元素,即我想得到结果为["1543","1578"]
我编写了以下代码来获取它,但它不起作用:
foldr (\acc x -> (x !! 2):acc) [] a
假设我有一个这样的列表
let a =[["Warning:","Route","1543","must","Stop","on","Link","11881"],["Warning:","Route","1578","must","Stop","on","Link","12171"]]
我想提取其中每个列表的第三个元素,即我想得到结果为["1543","1578"]
我编写了以下代码来获取它,但它不起作用:
foldr (\acc x -> (x !! 2):acc) [] a
这是一种使用列表理解和模式匹配来做你想做的事情的安全方法
let a' = [x | (_:(_:(x:_))) <- a]
这将遍历 list a
,查看所有长度至少为 的子列表3
,并返回每个此类子列表的第三个元素。
此解决方案将默默地忽略长度小于的子列表3
。为了解决这个问题并获得一些灵活性,您可以编写一个Maybe
在其返回类型中使用的函数;如果列表有第三个元素,则返回Just
第三个元素,否则返回Nothing
.
takeThird :: [a] -> Maybe a
takeThird (_:(_:(x:_))) = Just x
takeThird _ = Nothing
然后,您可以使用列表推导编写安全版本的操作:
let safea = [takeThird x | x <- a]
从中您可以创建一个可能会删除元素的版本:
let maybedropa = [x | Just x <- safea]
使用最近的镜头库 (Control.lens) 的替代解决方案是:
import Control.Lens
>a^..traverse.(element 2)
["1543","1578"]
不使用中缀表示法:
>toListOf (traverse.(element 2)) a
["1543","1578"]
'traverse' 访问可遍历的每个元素,在本例中为列表,并且 (element 2) 获取索引为 2 的元素,toListOf 将其全部收集到一个列表中。这种方法的优点是,如果以后决定使您的数据结构复杂化,您只需要编写自己的镜头接口(如果它还没有的话)。
假设你有 [[(Annotation, String)]] 而不是 [[String]] 并且你只想要上面的 String 部分。那么你需要做的就是 _2 元组访问器。
a^..traverse.(element 2)._2