I'm learning to deal with Lists and Tuples in F# and a problem came up. I have two lists: one of names and one with names,ages.
let namesToFind = [ "john", "andrea" ]
let namesAndAges = [ ("john", 10); ("andrea", 15) ]
I'm trying to create a function that will return the first age found in namesAndAges given namesToFind. Just the first.
So far I have the following code which returns the entire tuple ("john", 10).
let findInList source target =
let itemFound = seq { for n in source do
yield target |> List.filter (fun (x,y) -> x = n) }
|> Seq.head
itemFound
I tried using fst() in the returning statement but it does not compile and gives me "This expression was expected to have type 'a * 'b but here has type ('c * 'd) list"
Thanks for any help!
To get the first element of each tuple in a list: Declare a new variable and set it to an empty list. Use a for loop to iterate over the list of tuples. On each iteration, append the first tuple element to the new list.
That's because you can return a tuple by separating each item with a comma, as shown in the above example. “It is actually the comma which makes a tuple, not the parentheses,” the documentation points out. However, parentheses are required with empty tuples or to avoid confusion.
Approach #2 : Using zip and unpacking(*) operator This method uses zip with * or unpacking operator which passes all the items inside the 'lst' as arguments to zip function. Thus, all the first element will become the first tuple of the zipped list. Returning the 0th element will thus, solve the purpose.
To access the first element (12) of a list, we can use the subscript syntax [ ] by passing an index 0 . In Python lists are zero-indexed, so the first element is available at index 0 . Similarly, we can also use the slicing syntax [:1] to get the first element of a list in Python.
There are lots of functions in the Collections.List
module that can be used. Since there are no break
or a real return
statement in F#, it is often better to use some search function, or write a recursive loop-function. Here is an example:
let namesToFind = [ "john"; "andrea" ]
let namesAndAges = [ "john", 10; "andrea", 15 ]
let findInList source target =
List.pick (fun x -> List.tryFind (fun (y,_) -> x = y) target) source
findInList namesToFind namesAndAges
The findInList
function is composed of two functions from the Collections.List
module.
First we have the List.tryFind predicate list
function, which returns the first item for which the given predicate function returns true
.
The result is in the form of an option
type, which can take two values: None
and Some(x)
. It is used for functions that sometimes give no useful result.
The signature is: tryFind : ('T -> bool) -> 'T list -> 'T option
, where 'T
is the item type, and ('T -> bool)
is the predicate function type.
In this case it will search trough the target
list, looking for tuples where the first element (y
) equals the variable x
from the outer function.
Then we have the List.pick mapper list
function, which applies the mapper
-function to each one, until the first result that is not None
, which is returned.
This function will not return an option
value, but will instead throw an exception if no item is found. There is also an option
-variant of this function named List.tryPick
.
The signature is: pick : ('T -> 'U option) -> 'T list -> 'U
, where 'T
is the item type, 'U
is the result type, and ('T -> 'U option)
is the mapping function type.
In this case it will go through the source
-list, looking for matches in the target
array (via List.tryFind
) for each one, and will stop at the first match.
If you want to write the loops explicitly, here is how it could look:
let findInList source target =
let rec loop names =
match names with
| (name1::xs) -> // Look at the current item in the
// source list, and see if there are
// any matches in the target list.
let rec loop2 tuples =
match tuples with
| ((name2,age)::ys) -> // Look at the current tuple in
// the target list, and see if
// it matches the current item.
if name1 = name2 then
Some (name2, age) // Found a match!
else
loop2 ys // Nothing yet; Continue looking.
| [] -> None // No more items, return "nothing"
match loop2 target with // Start the loop
| Some (name, age) -> (name, age) // Found a match!
| None -> loop rest // Nothing yet; Continue looking.
| [] -> failwith "No name found" // No more items.
// Start the loop
loop source
(xs
and ys
are common ways of writing lists or sequences of items)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With