Reputation: 329
I have two lists of tuples which are as follows: [(String,Integer)]
and [(Float,Integer)]
. Each list has several tuples.
For every Integer
that has a Float
in the second list, I need to check if its Integer
matches the Integer
in the first list, and if it does, return the String
- although this function needs to return a list of String
s, i.e. [String]
with all the results.
I have already defined a function which returns a list of Integer
s from the second list (for the comparison on the integers in the first list).
This should be solvable using "high-order functions". I've spent a considerably amount of time playing with map
and filter
but haven't found a solution!
Upvotes: 2
Views: 10201
Reputation: 54584
Half of the problem is to get the string list if you have a single integer. There are various possibilities to do this, e.g. using filter
and map
. However you can combine both operations using a "fold":
findAll x axs = foldr extract [] axs where
extract (a,y) runningList | x==y = a:runningList
| otherwise = runningList
--usage:
findAll 2 [("a",2),("b",3),("c",2)]
--["c","a"]
For a fold you have a start value (here []
) and an operation that combines the running values successively with all list elements, either starting from the left (foldl
) or from the right (foldr
). Here this operation is extract
, and you use it to decide whether to add the string from the current element to the running list or not.
Having this part done, the other half is trivial: You need to get the integers from the (Float,Integer)
list, call findAll
for all of them, and combine the results.
Upvotes: 1
Reputation: 36339
One can see in this example how important it is to describe the problem accurately, not only to others but foremost to oneself.
You want the Strings from the first list, whose associated Integer does occur in the second list.
With such problems it is important to do the solutions in small steps. Most often one cannot write down a function that does it right away, yet this is what many beginners think they must do.
Start out by writing the type signature you need for your function:
findFirsts :: [(String, Integer)] -> [(Float, Integer)] -> [String]
Now, from the problem description, we can deduce, that we essentially have two things to do:
Hence, the basic skeleton of our function looks like:
findFirsts sis fis = map ... selected
where
selected = filter isWanted sis
isWanted :: (String, Integer) -> Bool
isWanted (_,i) = ....
You'll need the functions fst
, elem
and snd
to fill out the empty spaces.
Side note: I personally would prefer to solve this with a list comprehension, which results often in better readable (for me, anyway) code than a combination of map and filter with nontrivial filter criteria.
Upvotes: 2
Reputation: 68152
You have a list of Integers
from the second list. Let's call this ints
.
Now you need to do two things--first, filter the (String, Integer)
list so that it only contains pairs with corresponding integers in the ints
list and secondly, turn this list into just a list of String
.
These two steps correspond to the filter
and map
respectively.
First, you need a function to filter by. This function should take a (String, Integer)
pair and return if the integer is in the ints
list. So it should have a type of:
check :: (String, Integer) -> Bool
Writing this should not be too difficult. Once you have it, you can just filter the first list by it.
Next, you need a function to transform a (String, Integer)
pair into a String
. This will have type:
extract :: (String, Integer) -> String
This should also be easy to write. (A standard function like this actually exists, but if you're just learning it's healthy to figure it out yourself.) You then need to map this function over the result of your previous filter.
I hope this gives you enough hints to get the solution yourself.
Upvotes: 7