Haskell程序,用于查找列表中元素的位置

Haskell程序,用于查找列表中元素的位置,haskell,Haskell,我需要编写一个函数来查找列表中某个特定元素的位置。 我是这样写的: findPos list elt | list == [] = -1 | head list == elt = 0 | otherwise = 1 + (findPos (tail list) elt) 但是如果元素在列表中重复,该怎么办? 例如:list=[2,4,9,4,8]我想要元素“4”的位置,然后有2个位置:第二和第四。这是一个简单的函数吗?您可以让

我需要编写一个函数来查找列表中某个特定元素的位置。 我是这样写的:

findPos list elt | list == [] = -1
                 | head list == elt = 0
                 | otherwise = 1 + (findPos (tail list) elt)
但是如果元素在列表中重复,该怎么办?
例如:
list=[2,4,9,4,8]
我想要元素“4”的位置,然后有2个位置:第二和第四。这是一个简单的函数吗?

您可以让它返回一个索引列表。要使此功能正常工作,您需要在函数中更改以下几项:

  • 而不是-1返回空案例的空列表(返回-1是一个糟糕的习惯用法,您应该返回一个Maybe,因为这更有意义)
  • 您不应该递归调用
    findPos
    并将1添加到结果中,而应该创建一个使用计数器(从0开始)的helper函数,并将计数器增加1
  • 找到元素时,不应返回0,而应将计数器的当前值返回到列表尾部递归的结果(计数器增加)

  • 但是,此功能已存在于
    Data.List
    中,称为
    elemIndices
    。因此,除非这是一个纯粹的学习练习或家庭作业,否则您根本不需要重新实现它。

    您应该为匹配的元素返回一个索引列表

    简单实用的方法是首先使用
    zip[0..]
    对列表进行索引,然后在第二个元素上过滤压缩后的列表,最后删除第二个元素以保留索引

    -- first version
    findPos list elt = map fst $ filter ((elt==).snd) $ zip [0..] list
    -- second version, using list comprehensions
    findPos list elt = [index | (index, e) <- zip [0..] list, e == elt]
    
    ——第一版
    findPos list elt=map fst$filter((elt==).snd)$zip[0..]列表
    --第二个版本,使用列表理解
    
    findPos list elt=[index |(index,e)您还可以使用折叠:

    findPos :: Eq a => a -> [a] -> [Int]
    findPos elem = reverse . fst . foldl step ([],0) where
        step (is,i) e = (if e == elem then i:is else is, succ i) 
    
    在命令式语言中以一种类似while循环的方式编写是可能的,但相当冗长:

    findPos elem list = reverse $ thrd $ until finished step (list,0,[]) where
       finished (x,_,_) = null x
       step (e:es, c, acc) = (es, succ c, if e == elem then c:acc else acc) 
       thrd (_,_,x) = x 
    

    我认为最好的答案来自Kru。 如果元素在列表中,我建议使用另一种方法查找元素的第一个位置(不是所有位置)

    假设元素在列表中:

    indexOf elt list = length $ takeWhile (/=elt) list
    

    列表从elt的开始到第一次出现都会被遍历,但当找到elt时,列表就会停止。

    请咨询您的老师,了解他们想要什么。明智的选择包括(a)只返回找到的第一个位置;或(b)返回索引列表。如果颠倒参数的顺序,则函数可能对curry更有用,因为这样做:
    让findx=find'x'
    并使用一个函数在给定列表中搜索“x”。如果要创建一个设置为test的函数,并测试成员资格项目,例如白名单/黑名单。我想补充一点,使用帮助函数的原因是,通过传递计算的整个状态,可以实现“继续传递样式”(查找),可以自动优化以避免构建堆栈帧(相反,它以与循环相同的方式实现)。这不是必需的,但效率会更高。@Marcin:使用helper函数的原因是,如果没有它,在每次递归调用后,您必须增加结果列表中的每个元素,这将是1.可读性较差,更难理解;2.效率较低。我看不到与CPS的任何连接。(a)只有当您更改函数以返回列表时(这不是原始实现所做的);(b)如果您将所有内容都包装为参数,那么您最好捕获CPS的好处。@Marcin:问题是如何使其返回列表(或者如何让它处理多个索引,这意味着一个列表)。此外,如果您一直返回一个索引,并使用辅助函数使函数尾部递归,那么仍然不会涉及CPS。@Marcin:不,不是。CPS是当您将continuation作为显式参数(以函数的形式)传递时这会使调用成为尾部调用,但这并不意味着每个尾部调用都与CP相关。