Get positions of elements in list of strings in Haskell - haskell

my title might be a bit off and i'll try to explain a bit better what i'm trying to achieve.
Basically let's say i have a list:
["1234x4","253x4",2839",2845"]
Now i'd like to add all the positions of the strings which contain element 5 to a new list. On a current example the result list would be:
[1,3]
For that i've done similar function for elem:
myElem [] _ = False
myElem [x] number =
if (firstCheck x) then if digitToInt(x) == number then True else False else False
myElem (x:xs) number =
if (firstCheck x) then (if digitToInt(x) == number then True else myElem xs number) else myElem xs number
where firstCheck x checks that the checked element isn't 'x' or '#'
Now in my current function i get the first element position which contains the element, however my head is stuck around on how to get the full list:
findBlock (x:xs) number arv =
if myElem x number then arv else findBlock xs number arv+1
Where arv is 0 and number is the number i'm looking for.
For example on input:
findBlock ["1234x4","253x4",2839",2845"] 5 0
The result would be 1
Any help would be appreciated.

The function you want already exists in the Data.List module, by the name of findIndices. You can simply use (elem '5') as the predicate.
http://hackage.haskell.org/package/base-4.8.1.0/docs/Data-List.html#v:findIndices
If, for some reason, you're not allowed to use the built-in one, it comes with a very pretty definition (although the one actually used has a more complicated, more efficient one):
findIndices p xs = [ i | (x,i) <- zip xs [0..], p x]
By the way, I found this function by searching Hoogle for the type [a] -> (a -> Bool) -> [Int], which (modulo parameter ordering) is obviously the type such a function must have. The best way to find out of Haskell has something is to think about the type it would need to have and search Hoogle or Hayoo for the type. Hoogle is better IMO because it does slightly fuzzy matching on the type; e.g. Hayoo wouldn't find the function here by the type I've given, because it take the arguments in the reverse order.

An implementation of findIndices, for instructional purposes:
findIndices ok list = f list 0 where
f [] _ = []
f (x:xs) ix
| ok x = ix : f xs (ix+1)
| otherwise = f xs (ix+1)
Use it like findIndices (elem '5') my_list_o_strings

You're trying to work your way through a list, keeping track of where you are in the list. The simplest function for doing this is
mapWithIndex :: (Int -> a -> b) -> [a] -> [b]
mapWithIndex = mwi 0 where
mwi i _f [] = i `seq` []
mwi i f (x:xs) = i `seq` f i x : mwi (i+1) f xs
This takes a function and a list, and applies the function to each index and element. So
mapWithIndex (\i x -> (i, x)) ['a', 'b', 'c'] =
[(0,'a'), (1,'b'),(2,'c')]
Once you've done that, you can filter the list to get just the pairs you want:
filter (elem '5' . snd)
and then map fst over it to get the list of indices.
A more integrated approach is to use foldrWithIndex.
foldrWithIndex :: (Int -> a -> b -> b) -> b -> [a] -> b
foldrWithIndex = fis 0 where
fis i _c n [] = i `seq` n
fis i c n (x:xs) = i `seq` c i x (fis (i+1) c n xs)
This lets you do everything in one step.
It turns out that you can implement foldrWithIndex using foldr pretty neatly, which makes it available for any Foldable container:
foldrWithIndex :: (Foldable f, Integral i) =>
(i -> a -> b -> b) -> b -> f a -> b
foldrWithIndex c n xs = foldr go (`seq` n) xs 0 where
go x r i = i `seq` c i x (r (i + 1))
Anyway,
findIndices p = foldrWithIndex go [] where
go i x r | p x = i : r
| otherwise = r

Related

How to apply a function to a specific element of a list

How can I apply a function to only a single element of a list?
Any suggestion?
Example:
let list = [1,2,3,4,3,6]
function x = x * 2
in ...
I want to apply function only to the first occurance of 3 and stop there.
Output:
List = [1,2,6,4,3,6] -- [1, 2, function 3, 4, 3, 6]
To map or not to map, that is the question.
Better not to map.
Why? Because map id == id anyway, and you only want to map through one element, the first one found to be equal to the argument given.
Thus, split the list in two, change the found element, and glue them all back together. Simple.
See: span :: (a -> Bool) -> [a] -> ([a], [a]).
Write: revappend (xs :: [a]) (ys :: [a]) == append (reverse xs) ys, only efficient.
Or fuse all the pieces together into one function. You can code it directly with manual recursion, or using foldr. Remember,
map f xs = foldr (\x r -> f x : r) [] xs
takeWhile p xs = foldr (\x r -> if p x then x : r else []) [] xs
takeUntil p xs = foldr (\x r -> if p x then [x] else x : r) [] xs
filter p xs = foldr (\x r -> if p x then x : r else r) [] xs
duplicate xs = foldr (\x r -> x : x : r) [] xs
mapFirstThat p f xs = -- ... your function
etc. Although, foldr won't be a direct fit, as you need the combining function of the (\x xs r -> ...) variety. That is known as paramorphism, and can be faked by feeding tails xs to the foldr, instead.
you need to maintain some type of state to indicate the first instance of the value, since map will apply the function to all values.
Perhaps something like this
map (\(b,x) -> if (b) then f x else x) $ markFirst 3 [1,2,3,4,3,6]
and
markFirst :: a -> [a] -> [(Boolean,a)]
markFirst a [] = []
markFirst a (x:xs) | x==a = (True,x): zip (repeat False) xs
| otherwise = (False,x): markFirst a xs
I'm sure there is an easier way, but that's the best I came up with at this time on the day before Thanksgiving.
Here is another approach based on the comment below
> let leftap f (x,y) = f x ++ y
leftap (map (\x -> if(x==3) then f x else x)) $ splitAt 3 [1,2,3,4,3,6]
You can just create a simple function which multiples a number by two:
times_two :: (Num a) => a -> a
times_two x = x * 2
Then simply search for the specified element in the list, and apply times_two to it. Something like this could work:
map_one_element :: (Eq a, Num a) => a -> (a -> a) -> [a] -> [a]
-- base case
map_one_element _ _ [] = []
-- recursive case
map_one_element x f (y:ys)
-- ff element is found, apply f to it and add rest of the list normally
| x == y = f y : ys
-- first occurence hasnt been found, keep recursing
| otherwise = y : map_one_element x f ys
Which works as follows:
*Main> map_one_element 3 times_two [1,2,3,4,3,6]
[1,2,6,4,3,6]

Position of elements

the function should give me the position of the searched elements.
e. : index 'b' "dfbhjbd" -> [3,6]
I've got so far:
index b (x:xs) = length ( takeWhile ( /= b) xs )
but takeWhile will immediately stop after finding the matching elements. so following elements will be left out.
i tried something like this:
index b (x:xs) = length ( tak b xs )
where
tak b [] = []
tak b xs
| b /= x == x:tak b xs
| otherwise = [], tak b xs
Beside being unable to run the code because of parse error, it would not show the right results.
any suggestions?
you've already seen the problem with takeWhile - I can understand why you tried this (after all you want to use length) but maybe you should try to find a solution where you don't have to use length in the first place.
A good approach might be to keep track of the indizes while you traverse the input list and then look out for the elements equal to `b
if you want to use recursion then you can go all the way:
index :: (Eq a, Num t) => a -> [a] -> [t]
index b xs = index' 1 xs
where
index' _ [] = []
index' i (x:xs)
| b == x = i : index' (i+1) xs
| otherwise = index' (i+1) xs
example
λ> index 'b' "dfbhjbd"
[3,6]
as you can see I'm using a inner function here that takes care of the indizes and the recursion
another approach would be to use zip to get pairs of indizes and elements and then use filter and map to get the results out:
this corresponds to what you tried earlier
index :: (Eq a, Num t, Enum t) => a -> [a] -> [t]
index b xs =
map fst . filter ((== b) . snd) $ zip [1..] xs

Find the K'th element of a list using foldr

I try to implement own safe search element by index in list.
I think, that my function have to have this signature:
safe_search :: [a] -> Int -> Maybe a
safe_search xs n = foldr iteration init_val xs n
iteration = undefined
init_val = undefined
I have problem with implementation of iteration. I think, that it has to look like this:
safe_search :: [a] -> Int -> Maybe a
safe_search xs n = foldr iteration init_val xs n
where
iteration :: a -> (Int -> [a]) -> Int -> a
iteration x g 0 = []
iteration x g n = x (n - 1)
init_val :: Int -> a
init_val = const 0
But It has to many errors. My intuition about haskell is wrong.
you have
safe_search :: [a] -> Int -> Maybe a
safe_search xs n = foldr iteration init_val xs n
if null xs holds, foldr iteration init_val [] => init_val, so
init_val n
must make sense. Nothing to return, so
= Nothing
is all we can do here, to fit the return type.
So init_val is a function, :: Int -> Maybe a. By the definition of foldr, this is also what the "recursive" argument to the combining function is, "coming from the right":
iteration x r
but then this call must also return just such a function itself (again, by the definition of foldr, foldr f z [a,b,c,...,n] == f a (f b (f c (...(f n z)...))), f :: a -> b -> b i.e. it must return a value of the same type as it gets in its 2nd argument ), so
n | n==0 = Just x
That was easy, 0-th element is the one at hand, x; what if n > 0?
| n>0 = ... (n-1)
Right? Just one more step left for you to do on your own... :) It's not x (the list's element) that goes on the dots there; it must be a function. We've already received such a function, as an argument...
To see what's going on here, it might help to check the case when the input is a one-element list, first,
safe_search [x] n = foldr iteration init_val [x] n
= iteration x init_val n
and with two elements,
[x1, x2] n = iteration x1 (iteration x2 init_val) n
-- iteration x r n
Hope it is clear now.
edit: So, this resembles the usual foldr-based implementation of zip fused with the descending enumeration from n down, indeed encoding the more higher-level definition of
foo xs n = ($ zip xs [n,n-1..]) $
dropWhile ((>0) . snd) >>>
map fst >>>
take 1 >>> listToMaybe
= drop n >>> take 1 >>> listToMaybe $ xs
Think about a few things.
What type should init_val have?
What do you need to do with g? g is the trickiest part of this code. If you've ever learned about continuation-passing style, you should probably think of both init_val and g as continuations.
What does x represent? What will you need to do with it?
I wrote up an explanation some time ago about how the definition of foldl in terms of foldr works. You may find it helpful.
I suggest to use standard foldr pattern, because it is easier to read and understand the code, when you use standard functions:
foldr has the type foldr :: (a -> b -> b) -> [a] -> b -> [b],
where third argument b is the accumulator acc for elements of your list [a].
You need to stop adding elements of your list [a] to acc after you've added desired element of your list. Then you take head of the resulting list [b] and thus get desired element of the list [a].
To get n'th element of the list xs, you need to add length xs - n elements of xs to the accumulator acc, counting from the end of the list.
But where to use an iterator if we want to use the standard foldr function to improve the readability of our code? We can use it in our accumulator, representing it as a tuple (acc, iterator). We subtract 1 from the iterator each turn we add element from our initial list xs to the acc and stop to add elements of xs to the acc when our iterator is equal 0.
Then we apply head . fst to the result of our foldr function to get the desired element of the initial list xs and wrap it with Just constructor.
Of course, if length - 1 of our initial list xs is less than the index of desired element n, the result of the whole function safeSearch will be Nothing.
Here is the code of the function safeSearch:
safeSearch :: Int -> [a] -> Maybe a
safeSearch n xs
| (length xs - 1) < n = Nothing
| otherwise = return $ findElem n' xs
where findElem num =
head .
fst .
foldr (\x (acc,iterator) ->
if iterator /= 0
then (x : acc,iterator - 1)
else (acc,iterator))
([],num)
n' = length xs - n

Get first item matching a criteria using foldr

I am giving my self exercises and wondering if there is a way to find the first item from left in the list matching a certain criteria using just foldr? I want the recursion to stop when the first item is found (I know I could probably combine using take) but I am curious to know if it is possible to do just using foldr?
firstFind (\x -> x > 1000) [] xs
The problem: find f and b.
firstFind :: (a -> Bool) -> [a] -> Maybe a
firstFind p list = foldr f b list
where f = ???
b = ???
We want:
firstFind p [] = Nothing
but we also have
firstFind p []
= def. firstFind
foldr f b []
= def. foldr
b
from which we see what b must be.
Further, take list = x:xs
firstFind p list
= def. firstFind
foldr f b (x:xs)
= def. foldr
f x (foldr f b xs)
= def. firstFind
f x (firstFind p xs)
Now, we just need to find f so that this chooses the first match.
Recall that f can depend on p. What should f return when p x is true? What in the opposite case?
where -- f :: a -> Maybe a -> Maybe a
f x y = ???
(Note: above I wrote the type signature for f for clarity, but you don't have to include it in your code. If you add it, uncommented, you will trip into a type variable confusion: that a is not the same a as in findFirst because it is generalized locally -- since you are just beginning, ignore this and simply remove it for the moment being.)

Haskell list: Replacing elements given their locations in the list

I'm fairly new to Haskell and trying to figure out how I would write a Function to do this and after combing Google for a few hours I'm at a loss on how to do it.
Given the following two lists in Haskell
[(500,False),(400,False),(952,True),(5,False),(42,False)]
[0,2,3]
How would I change the Boolean of the First list at each location given by the second list to a Value of True for an Output of
[(500,True),(400,False),(952,True),(5,True),(42,False)]
This is how I would do it (assumes the list of indexes to replace is sorted).
First we add an index list alongside the list of indexes to replace and the original list.
Then we recurse down the list and when we hit the next index to replace we replace the boolean and recurse on the tail of both all three lists. If this is not an index to
replace we recurse on the entire replacement index list and the tail of the other two lists.
setTrue :: [Int] -> [(a, Bool)] -> [(a, Bool)]
setTrue is xs = go is xs [0..] -- "Index" the list with a list starting at 0.
where
go [] xs _ = xs -- If we're out of indexes to replace return remaining list.
go _ [] _ = [] -- If we run out of list return the empty list.
go indexes#(i:is) (x:xs) (cur:cs)
| i == cur = (fst x, True) : go is xs cs -- At the next index to replace.
| otherwise = x : go indexes xs cs -- Otherwise, keep the current element.
This is basically the same as Andrew's approach, but it doesn't use an additional index list, and is a little bit more inspired by the traditional map. Note that unlike map, the provided function must be a -> a and cannot be a -> b.
restrictedMap :: (a -> a) -> [Int] -> [a] -> [a]
restrictedMap f is xs = go f is xs 0
where
go f [] xs _ = xs
go f _ [] _ = []
go f ind#(i:is) (x:xs) n
| i == n = f x : go f is xs (n+1)
| otherwise = x : go f ind xs (n+1)
setTrue = restrictedMap (\(x,_) -> (x, True))
Straightforward translation from the description will be:
setIndexTrue f a = [(x, p || i `elem` f) | (i, (x,p)) <- zip [0..] a]
Or using the fantastic lens library:
setTrue :: [(a,Bool)] -> Int -> [(a,Bool)]
setTrue xs i = xs & ix i . _2 .~ True
setTrues :: [(a,Bool)] -> [Int] -> [(a,Bool)]
setTrues = foldl setTrue
Since the approach I would use is not listed:
setTrue spots values = let
pattern n = replicate n False ++ [True] ++ Repeat False
toSet = foldl1 (zipWith (||)) $ map pattern spots
in zipWith (\s (v,o) -> (v, o || s)) toSet values

Resources