Haskell return position of searched item - haskell

I have the following Haskell code, which returns the an instance of the requested element from the list (just the first instance) or returns 0 if the element is not present. I am trying to return the position of the element in the list instead but don't know how to (I am very new to programming).
e.g. 'm' 'some' is returning m but I want it to return 3.
findMe x [] = 0
findMe x (y:ys) = if x == y
then x
else findMe x ys

Try this. If 0 is returned because element not present, I assume that it is 1 index start.
findMe x list = findMeP list 1
where
findMeP [] _ = 0
findMeP (y:ys) n
| x == y = n
| otherwise = findMeP ys (n + 1)
As a demo, take a look at this.

Although the previous answer is correct, here is a solution that I'd prefer since it makes use of basic building blocks from the base library and avoids explicit recursion.
import Data.List (find) {- for find :: (a -> Bool) -> [a] -> Maybe a -}
findMe :: Eq a => a -> [a] -> Maybe (Int, a)
findMe x = find ((== x).snd) . zip [1..]
The function returns both the element and its index, counting from zero, wrapped in a Maybe type. If the element is not found, Nothing is returned.
To extract the element or the index alone one can map the fst and snd functions over the Maybe result:
findMeIndex = fmap fst . findMe
findMeElem = fmap snd . findMe
Example:
findMe 'c' ['a','b','c','d'] == Just (2,'c')
findMe 'z' ['a','b','c','d'] == Nothing
findMeIndex 'c' ['a','b','c','d'] == Just 2
findMeIndex 'z' ['a','b','c','d'] == Nothing
If you need to start counting from 1, you can replace [0..] with [1..]. In either case, wrapping the result in a Maybe is preferred to returning some special value signaling the absence of the element (say -1 or 0), because then the user cannot ever mistake to interpret your result. For example, if you count from 1 and return 0 on failure, and someone uses your function erroneously thinking that you count from 0, they may interpret a failure as if the element was found at the first position. Here instead, the user is forced to handle the failure case explicitly.
The function works as follows. zip [0..] produces a list of pairs coupling each element with its index, starting from zero ([0..] is the infinite list [0,1,2,3,..]). Then, find scans the list (in exactly the same way as OP's original code), returning the first element for which the function ((== x).snd) returns True, wrapped in a Maybe type, if found, or Nothing otherwise. Which element does find look for? Remember that find is fed with a list of pairs. So by composing the snd function with (== x) we find the pair whose second component is equal to x

Related

Haskel '!!' defined in foldl

I just started learning Haskell and I'm trying to define the "Get n'th element of list" (with the !! operator) in a function which uses foldl. I now defined it without foldl, just making use of recursion. I wondered if anybody could tell me how to change the code I have to a function with foldl, and could describe what is happening. Thanks in advance!
get 1 (x:_) = x
get i (_:xs) = elementAt'' (i - 1) xs
A couple of notes:
First note that you want get 1 to return the first element in your list, that's not the common choice in many languages including Haskell ([2, 3, 5] !! 1 = 3).
Second, although elementAt is a recursive function over lists, it can be defined more efficiently in the old fashion recursive way. fold functions are not good choices here, because fold goes through every element of the list. But we want elementAt recursion to stop the moment that we find the element.
Given this, here is how you can implement elementAt recursively:
elementAt :: Int -> [a] -> a
elementAt i (x:xs) = if i == 1 then x else elementAt (i-1) xs
And here's the implementation using foldl:
elementAt' :: Int -> [a] -> a
elementAt' i (x:xs) =
snd $
foldl
(\(j, a) b ->
if j < 1 then (j-1, a) else (j-1, b))
(i-1, x)
xs
The seed value of foldl is a tuple: (i-1, x) where x is the head of the list.
Note that the return result of fold functions must be of the same type of their seed. Hence here foldl returns a tuple: (j-1, a) where a is the final result, if the index is found; otherwise (j-1, b) where b is the current element of the list.
You can see how foldl goes through every element of the list even after it found the element at index that we were looking for (it keeps returning the previous result a that will be the final result).
PS. These elementAt functions are not handling the case for empty lists or when i is greater than the length of the list; hence they're not exhaustive.
I can see the following, a bit cryptic way of using foldl for your purpose (it is using zero-based indexing, but can be changed easily to 1-based):
get i lst=
snd $
foldl (\p (j, y) -> if j == i then (j,y) else p ) (0, 0) (zip [0,1..] lst)
The foldl part is working with tuples (index, element), whose list is generated by zipping the given list with indices list. The function passed to foldl as first argument is comparing the index of the desired element with the index with currently passed, and returning the current element if the index is matching, or the previous element otherwise. Then, in the end by using snd only the element part of the tuple is returned.

Search for String in both elements of pairs

Again I am stuck.
I have a list of pairs of strings [(String, String)] and want to look for another String in it.
When the substring matches the first in the tuple, I'd like to return the second one and vice versa.
I had some ideas but again, I don't know how to correctly apply functions in Haskell.
My first idea was to use map but that wouldn't really be able to give me a String as a result, would it?
I was thinking about using filter. First searching the substring in the first of the pair and then in the second ones.
This is as far as I got:
search :: String -> [(String, String)] -> String
search substr xs = filter(==substr) xs.fst
And it doesn't even work :/
I'd be thankful for any kind of advice!
Thanks
I would suggest you to wrap the return type in Maybe in case the substring isn't found.
search :: Eq a => a -> [(a, a)] -> Maybe a
search s xs = case lookup s xs of
Just x -> Just x
Nothing -> lookup s xs'
where xs' = map swap xs
If you don't want to wrap it with Maybe, just use the fromJust function and change the type signature accordingly. In the above code, you are using the library defined lookup function. And in case the lookup fails in the first search you exchange the tuples and again perform the lookup operation. Also, Don't forget to import swap from Data.Tuple.
Demo in ghci:
ghci > let a = [("hi","bye"),("cat", "dog")]
ghci > search "hi" a
Just "bye"
ghci > search "dog" a
Just "cat"
You can call lookup on the list, and then call lookup after swapping each tuple in the list. But this means possibly traversing the list twice.
lookup' k = foldl acc Nothing
where
acc (Just x) _ = Just x
acc _ (a,b) | k == b = Just a | k == a = Just b | otherwise = Nothing
This way you traverse the list only once. This version doesn't terminate on infinite lists if the element is present. You can write it using foldr, but that for that version, lookup' 0 [(0,1), undefined] == undefined as opposed to the preferred behavior.
You can also write it using explicit recursion. For once, using explicit recursion is better! It covers both of the cases covered above:
lookup'' k [] = Nothing
lookup'' k ((a,b):xs)
| k == a = Just b
| k == b = Just a
| otherwise = lookup'' k xs
>lookup'' 1 [(1,0), undefined]
Just 0
>lookup'' 1 (zip [0..] [0..])
Just 1
user2407038's solution, lookup'' is the most efficient since it traverses the list only once, and terminates early when a match is found. It can be written without explicit recursion as follows:
import Control.Monad ( msum )
lookup'' k = msum . map match
where match (a, b) | k == a = Just b
| k == b = Just a
| otherwise = Nothing

How can i count elements of a tuple in Haskell?

So i've got a list of tuples like this one :
xs = [("a","b"),("a","c"),("b","d")
and i want a function that counts the number of times a certain value appears in the first position of the tuple. If i used the list xs and the letter 'a', it would return the value 2, because the letter 'a' appears two times in the first position of the tuple. This function shouldn't be recursive.
So what i've got is this:
f xs = (fst $ unzip xs) / length(xs)
Now i have all the elements down on a list. this would be easy if it was recursive, but if i don't want it that way, how can i do it ?
If we're not using recursion, we need to use some higher order functions. In particular, filter looks helpful, it removes elements who don't satisfy some condition.
Well if we use filter we can get a list of all elements with the first element being the correct thing.
count :: Eq a => [(a, b)] -> Int
count x = length . filter ((== x) . fst)
I suppose since you're studying, you should work to understand some folds, start with
count x = foldr step 0
where step (a, b) r | a == x = 1 + r
| otherwise = r
If you map the first elements into a list find all occurences of your value and count the length of the resulting list:
countOccurences :: Eq a => a -> [(a, b)] -> Int
countOccurences e = length . filter ((==)e) . map fst

Haskell: Are there other things like "_" that you can use to say that you don't care what the value is?

So I wrote a hexapawn game and I'm trying to make a function that returns True if the board is in a winning state, it looks like this at the moment:
checkWin :: BoardState -> Bool
checkWin b1#(blackPieces,whitePieces,turn,size,win)
|(length blackPieces) == 0 = True
|(length whitePieces) == 0 = True
|length (generateMoves b1) == 0 = True
|otherwise = False
So this works if there are no black or white pieces left or if no one can make a move but it doesn't work if an opposing pawn reaches the end of the board(another way to win in hexapawn). The variables blackPieces and whitePieces are list of coordinates ie [(1,1),(2,1),(3,1)] of where those pawns are on the board of size n (turn is true if its whites turn)
I was tempted to add these conditions to the method but the compiler didn't like it.
|(_,1) `elem` whitePieces = True
|(_,size) `elem` blackPieces = True
Is there any other way to say "Are there any tuples in whitePieces who's second element is a 1(i.e reached the other side of the board)."
Thanks in advance for your helpful comments.
So we want a function that receives a list of something [a], a predicate over somethings (a->Bool) and returns a Bool. A quick check on Hoogle and we get back
any :: (a -> Bool) -> [a] -> Bool
Applied to a predicate and a list, any determines if any element of
the list satisfies the predicate. For the result to be False, the list must be finite
So
(_,1) `elem` whitePieces
becomes
any (\(_, x) -> x == 1) whitePieces
or (as eternalmatt reminds me)
any (==1) ( map snd whitePieces )
and so on
By the way, the best way to check is a list is empty is via pattern matching or the null function. The length == 0 method will walk through all of the linked list and might even enter an infinite loop if the list is infinite.
you could for example use filter:
not $ null (filter wincond whitePieces)
where wincond x = snd x == 1
this expression is True if the list of whitePieces with second entry 1 is not an empty list ([])
or you could use map:
or (map (\x -> snd x == size) blackPieces)
this expression does: first it checks if an element of blackPieces has second entry equal to size and gives a list of Trues and Falses ([Bool]) then the function or gives True if any of them is True
The reason the compiler doesn't like that is because _ only works on pattern matches. The underscore means "I could bind this portion of the data to a variable name, but I don't need to."
The way you tried to use it is different: you basically said "does there exist an x such that (x,1) is an element of whitePieces?"
Can you see the difference? See also Haskell 2010 > Expressions # Patter Matching

Haskell program to find the position of an element in a list

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?
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]
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.
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
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.

Resources