问题
I need to write a function to find the position of one specific element in a list. i was writing like this:
findPos list elt | list == [] = -1
| head list == elt = 0
| otherwise = 1 + (findPos (tail list) elt)
but how to do in the case that the element is repeated within the list?
For example: list= [2,4,9,4,8]
and i want the position of the element "4", then has 2 position : second and fourth. How would be a simply function for that?
回答1:
You should return a lazy-evaluated list of indexes for elements that are matching.
The easy functional way of doing it is to index first the list using zip [0..]
then filter that zipped list on the second element and finaly remove the second elements just to keep the indexes.
-- 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]
回答2:
You could make it return a list of indices. To make this work, you'll need to change a couple of things in the function:
- Instead of -1 return the empty list for the empty case (returning -1 is a bad idiom anyway, you should have returned a Maybe instead as that is more meaningful).
- Instead of calling
findPos
recursively and adding 1 to the result, you should create a helper function taking a counter (which starts at 0) and increase the counter by 1. - When you find the element, instead of returning 0, you should return the current value of the counter prepended to the result of recursing on the tail of the list (with an increased counter).
However this functionality already exists in Data.List
and is called elemIndices
. So unless this is a pure learning exercise or homework, you don't need to reimplement this at all.
回答3:
You can also use a fold:
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)
Writing in a way that feels like a while loop in imperative languages is possible, but rather verbose:
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
回答4:
I think the best answer is from Kru. I suggest another idea for finding the first position of a element (not all positions), if this element is in the list.
Assume the element is in the list :
indexOf elt list = length $ takeWhile (/=elt) list
The list is traversed from the beginning to the first occurrence of elt, but it stops when the elt is found.
来源:https://stackoverflow.com/questions/6322053/haskell-program-to-find-the-position-of-an-element-in-a-list