我需要编写一个函数来查找列表中某个特定元素的位置。 我写的是这样的:
findPos list elt | list == [] = -1
| head list == elt = 0
| otherwise = 1 + (findPos (tail list) elt)
但是如果元素在列表中重复怎么办?
例如:list= [2,4,9,4,8]
我想要元素“4”的位置,然后有2个位置:第二个和第四个。怎么会是一个简单的功能呢?
答案 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)
你可以让它返回一个索引列表。为了使这项工作,您需要在函数中更改一些内容:
findPos
并将1加到结果中,而是应该创建一个辅助函数来取一个计数器(从0开始)并将计数器增加1。但是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时它会停止。