在列表中查找元素及其索引

Sté*_*ent 2 haskell

我需要让列表的元素满足谓词这些元素的索引.我可以这样做:

import           Data.List (findIndices)

list :: [Int]
list = [3,2,4,1,9]

indices = findIndices (>2) list
elems = [list!!i | i <- indices]
-- same as: elems = filter (>2) list
Run Code Online (Sandbox Code Playgroud)

是不是有一个包提供了一个功能,以"一次性"给出元素及其索引?我很惊讶我在某处找不到这个功能.否则,如何做这样的功能,改进我上面的代码?我不相信这段代码是最优的,因为它以某种方式访问​​列表的元素两次.我快速浏览了一下源代码,findIndices但我还不明白.

Ry-*_*Ry- 7

您可以!!通过过滤(索引,元素)元组列表来提高效率 - 避免访问.

let (indices, elems) = unzip [(i, x) | (i, x) <- zip [0..] list, x > 2]
Run Code Online (Sandbox Code Playgroud)

分成适当的功能:

findItems :: (a -> Bool) -> [a] -> [(Int, a)]
findItems predicate = filter (predicate . snd) . zip [0..]
Run Code Online (Sandbox Code Playgroud)
let (indices, elems) = unzip $ findItems (>2) list
Run Code Online (Sandbox Code Playgroud)

可能会有一种更简单的方式,我很乐意找到它:)


lef*_*out 6

我觉得Ry的建议很好.对于更直接的,特别是更通用的,您可以使用lens工具:

Prelude> import Control.Lens as L
Prelude L> import Control.Arrow as A
Prelude L A> ifoldr (\i x -> if x>2 then (i:)***(x:) else id) ([],[]) [3,2,4,1,9]
([0,2,4],[3,4,9])
Run Code Online (Sandbox Code Playgroud)

这也可以立即用于数组(索引提取更有用)

Prelude L A> import qualified Data.Vector as V
Prelude L A V> ifoldr (\i x -> if x>2 then (i:)***(x:) else id) ([],[]) $ V.fromList [3,2,4,1,9]
([0,2,4],[3,4,9])
Run Code Online (Sandbox Code Playgroud)

......即使是未装箱的,但不是Foldable:

Prelude L A V> import qualified Data.Vector.Unboxed as VU
Prelude L A V VU> import Data.Vector.Generic.Lens as V
ifoldrOf vectorTraverse (\i x -> if x>2 then (i:)***(x:) else id) ([],[]) $ VU.fromList [3,2,4,1,9]
([0,2,4],[3.0,4.0,9.0])
Run Code Online (Sandbox Code Playgroud)