Assuming I have a list like this
let a =[["Warning:","Route","1543","must","Stop","on","Link","11881"],["Warning:","Route","1578","must","Stop","on","Link","12171"]]
And I want to extract third element of each list inside it, i.e I want to get the resultant as ["1543","1578"]
I wrote the following piece of code for obtaining it, but it is not working:
foldr (\acc x -> (x !! 2):acc) [] a
Here's a safe way to do what you want to do using a list comprehension and pattern matching
let a' = [x | (_:(_:(x:_))) <- a]
This will iterate over the list a, look at all sublists of length at least 3, and return the third element of each such sublist.
This solution will silently ignore sublists of length less than 3. To work around this, and gain some flexibility, you can write a function that uses Maybe in its return type; if the list has a third element, it will return Just the third element, otherwise it will return Nothing.
takeThird :: [a] -> Maybe a
takeThird (_:(_:(x:_))) = Just x
takeThird _ = Nothing
Then, you can write a safe version of your operation using a list comprehension:
let safea = [takeThird x | x <- a]
And from that you can create a version that may drop elements:
let maybedropa = [x | Just x <- safea]
An alternative solution using the recent lens library (Control.lens) would:
import Control.Lens
>a^..traverse.(element 2)
["1543","1578"]
Not using the infix notation:
>toListOf (traverse.(element 2)) a
["1543","1578"]
'traverse' visits each element of a traversable, in this case the list, and (element 2) grabs the element with the 2 index and toListOf gathers it all into a list. This method has the advantage that if decide to complicate your data structure later you just need to write your own lens interface to it if it does not already have one.
Let say instead of a [[String]] you have [[(Annotation, String)]] and you just want the String portion just like above. Then all you need to do is the _2 tuple accessor.
a^..traverse.(element 2)._2
Related
I want the intersection between two lists but it is only prints when they are at the same position.
inter [] _ = []
inter _ [] = []
inter (x:xs) (y:ys) = if (x == y) then x:inter xs ys else inter xs ys
As already mentioned in the comments, your function iterates over both lists at the same time and appends elements to the result list, if the same element appears in both lists at the same location.
From what I've understood, what you really want to do is to add all elements from the first list that appear anywhere in the second list. So you may want to define (or use) another function that checks whether an element appears somewhere in a list, e.g. if you are having a list of Ints:
elem :: Int -> [Int] -> Bool
or if you are already aware of what type classes are:
elem :: Eq a => a -> [a] -> Bool
Using that function, you can process the first list element-wise and filter out all elements from that list that appear somewhere in the second list.
As you are obviously trying to learn Haskell, I do not want to spoil the experience for you and provide a more complete solution.
I want to create a function that returns every third int from a list of ints without using any predefined functions. For example, everyThird [1,2,3,4,5] --> [1,4]
everyThird:: [a] -> [a]
Could I just continue to iterate over the list using tail and appending to a new list every third call? I am new to Haskell and very confused with all of this
One other way of doing this is to handle three different base cases, in all of which we're at the end of the list and the list is less than three elements long, and one recursive case, where the list is at least three elements long:
everyThird :: [a] -> [a]
everyThird [] = []
everyThird [x] = [x]
everyThird [x, _] = [x]
everyThird (x:_:_:xs) = x:everyThird xs
You want to do exactly what you said: iterate over the list and include the element only on each third call. However, there's a problem. Haskell is a funny language where the idea of "changing" a variable doesn't make sense, so the usual approach of "have a counter variable i which tells us whether we're on the third element or not" won't work in the usual way. Instead, we'll create a recursive helper function to maintain the count for us.
everyThird :: [Int] -> [Int]
everyThird xs = helper 0 xs
where helper _ [] = []
helper 0 (x : xs) = x : helper 2 xs
helper n (_ : xs) = helper (n - 1) xs
We have three cases in the helper.
If the list is empty, stop and return the empty list.
If the counter is at 0 (that is, if we're on the third element), make a list starting with the current element and ending with the rest of the computation.
If the counter is not at zero, count down and continue iteration.
Because of the way pattern matching works, it will try these three statements in order.
Notice how we use an additional argument to be the counter variable since we can't mutate the variable like we would in an imperative language. Also, notice how we construct the list recursively; we never "append" to an existing list because that would imply that we're mutating the list. We simply build the list up from scratch and end up with the correct result on the first go round.
Haskell doesn't have classical iteration (i.e. no loops), at least not without monads, but you can use similar logic as you would in a for loop by zipping your list with indexes [0..] and applying appropriate functions from Data.List.
E.g. What you need to do is filter every third element:
everyThirdWithIndexes list = filter (\x -> snd x `mod` 3 == 0) $ zip list [0..]
Of course you have to get rid of the indexes, there are two elegant ways you can do this:
everyThird list = map (fst) . everyThirdWithIndexes list
-- or:
everyThird list = fst . unzip . everyThirdWithIndexes list
If you're not familiar with filter and map, you can define a simple recursion that builds a list from every first element of a list, drops the next two and then adds another from a new function call:
everyThird [] = [] -- both in case if the list is empty and the end case
everyThird (x:xs) = x : everyThird (drop 2 xs)
EDIT: If you have any questions about these solutions (e.g. some syntax that you are not familiar with), feel free to ask in the comments. :)
One classic approach:
everyThird xs = [x | (1,x) <- zip (cycle [1..3]) xs]
You can also use chunksOf from Data.List.Split to seperate the lists into chunks of 3, then just map the first element of each:
import Data.List.Split
everyThird :: [a] -> [a]
everyThird xs = map head $ chunksOf 3 xs
Which works as follows:
*Main> everyThird [1,2,3,4,5]
[1,4]
Note: You may need to run cabal install split to use chunksOf.
let's say i have a list like this:
["Questions", "that", "may", "already", "have", "your", "correct", "answer"]
and want to have this:
[("Questions","that"),("may","already"),("have","your"),("correct","answer")]
can this be done ? or is it a bad Haskell practice ?
For a simple method (that fails for a odd number of elements) you can use
combine :: [a] -> [(a, a)]
combine (x1:x2:xs) = (x1,x2):combine xs
combine (_:_) = error "Odd number of elements"
combine [] = []
Live demo
Or you could use some complex method like in an other answer that I don't really want to understand.
More generic:
map2 :: (a -> a -> b) -> [a] -> [b]
map2 f (x1:x2:xs) = (f x1 x2) : map2 f xs
map2 _ (_:_) = error "Odd number of elements"
map2 _ [] = []
Here is one way to do it, with the help of a helper function that lets you drop every second element from your target list, and then just use zip. This may not have your desired behavior when the list is of odd length since that's not yet defined in the question.
-- This is just from ghci
let my_list = ["Questions", "that", "may", "already", "have", "your", "correct", "answer"]
let dropEvery [] _ = []
let dropEvery list count = (take (count-1) list) ++ dropEvery (drop count list) count
zip (dropEvery my_list 2) $ dropEvery (tail my_list) 2
[("Questions","that"),("may","already"),("have","your"),("correct","answer")
The helper function is taken from question #6 from 99 Questions., where there are many other implementations of the same idea, probably many with better recursion optimization properties.
To understand dropEvery, it's good to remember what take and drop each do. take k some_list takes the first k entries of some_list. Meanwhile drop k some_list drops the first k entries.
If we want to drop every Nth element, it means we want to keep each run of (N-1) elements, then drop one, then do the same thing again until we are done.
The first part of dropEvery does this: it takes the first count-1 entries, which it will then concatenate to whatever it gets from the rest of the list.
After that, it says drop count (forget about the N-1 you kept, and also the 1 (in the Nth spot) that you had wanted to drop all along) -- and after these are dropped, you can just recursively apply the same logic to whatever is leftover.
Using ++ in this manner can be quite expensive in Haskell, so from a performance point of view this is not so great, but it was one of the shorter implementations available at that 99 questions page.
Here's a function to do it all in one shot, which is maybe a bit more readable:
byTwos :: [a] -> [(a,a)]
byTwos [] = []
byTwos xs = zip firsts seconds
where enumerated = zip xs [1..]
firsts = [fst x | x <- enumerated, odd $ snd x]
seconds = [fst x | x <- enumerated, even $ snd x]
In this case, I started out by saying this problem will be easy to solve with zip if I just already had the list of odd-indexed elements and the list of even-indexed elements. So let me just write that down, and then worry about getting them in some where clause.
In the where clause, I say first zip xs [1..] which will make [("Questions", 1), ("that", 2), ...] and so on.
Side note: recall that fst takes the first element of a tuple, and snd takes the second element.
Then firsts says take the first element of all these values if the second element is odd -- these will serve as "firsts" in the final output tuples from zip.
seconds says do the same thing, but only if the second element is even -- these will serve as "seconds" in the final output tuples from zip.
In case the list has odd length, firsts will be one element longer than seconds and so the final zip means that the final element of the list will simply be dropped, and the result will be the same as though you called the function on the front of the list (all but final element).
A simple pattern matching could do the trick :
f [] = []
f (x:y:xs) = (x,y):f(xs)
It means that an empty list gives an empty list, and that a list of a least two elements returns you a list with a couple of these two elements and then application of the same reasoning with what follows...
Using chunk from Data.List.Split you can get the desired result of pairing every two consecutive items in a list, namely for the given list named by xs,
import Data.List.Split
map (\ys -> (ys!!0, ys!!1)) $ chunk 2 xs
This solution assumes the given list has an even number of items.
Is there any built-in function to replace an element at a given index in haskell?
Example:
replaceAtIndex(2,"foo",["bar","bar","bar"])
Should give:
["bar", "bar", "foo"]
I know i could make my own function, but it just seems it should be built-in.
If you need to update elements at a specific index, lists aren't the most efficient data structure for that. You might want to consider using Seq from Data.Sequence instead, in which case the function you're looking for is update :: Int -> a -> Seq a -> Seq a.
> import Data.Sequence
> update 2 "foo" $ fromList ["bar", "bar", "bar"]
fromList ["bar","bar","foo"]
As far as I know (and can find) it does not exist by default. However, there exists splitAt in Data.List so:
replaceAtIndex n item ls = a ++ (item:b) where (a, (_:b)) = splitAt n ls
This is O(N) though. If you find yourself doing this a lot, look at another datatype such as array.
There is actual arrays, but lists are really singly linked lists and the notion of replacing an element is not quite as obvious (and accessing an element at a given index may indicate that you shouldn't be using a list, so operations that might encourage it are avoided).
Try this solution:
import Data.List
replaceAtIndex :: Int -> a -> [a] -> [a]
replaceAtIndex i x xs = take i xs ++ [x] ++ drop (i+1) xs
It works as follows:
get the first i items, add the value 'x', add the rest of i+1 items
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.