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

时间:2011-06-12 12:56:28

标签: haskell

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

findPos list elt | list == [] = -1
                 | head list == elt = 0
                 | otherwise = 1 + (findPos (tail list) elt)

但是如果元素在列表中重复怎么办? 例如:list= [2,4,9,4,8]我想要元素“4”的位置,然后有2个位置:第二个和第四个。怎么会是一个简单的功能呢?

4 个答案:

答案 0 :(得分:9)

您应该为匹配的元素返回一个延迟评估的索引列表。

这样做的简单方法是首先使用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]

答案 1 :(得分:5)

你可以让它返回一个索引列表。为了使这项工作,您需要在函数中更改一些内容:

  1. 而不是-1返回空列表的空列表(无论如何返回-1都是一个不好的习惯用法,你应该返回一个Maybe而不是因为那更有意义)。
  2. 不是递归地调用findPos并将1加到结果中,而是应该创建一个辅助函数来取一个计数器(从0开始)并将计数器增加1。
  3. 当你找到元素而不是返回0时,你应该返回列表尾部的递归结果前面的计数器的当前值(使用增加的计数器)。
  4. 但是Data.List中已存在此功能,称为elemIndices。因此,除非这是一个纯粹的学习练习或家庭作业,否则你根本不需要重新实现这一点。

答案 2 :(得分:1)

您也可以使用折叠:

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 

答案 3 :(得分:0)

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

假设元素在列表中:

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

列表从elt的开头到第一次出现遍历,但是当找到elt时它会停止。