Return the first value of the tuple list

I am learning to deal with lists and tuples in F #, and there was a problem. I have two lists: one of the names and one with the names, age.

let namesToFind = [ "john", "andrea" ] let namesAndAges = [ ("john", 10); ("andrea", 15) ] 

I am trying to create a function that will return the first age found in the AndAndAges names, given the ToFind names. Only the first one.

So far, I have the following code that returns the whole set ("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 returned expression, but it does not compile and does not give me "This expression should have type 'a *' b, but there is type ('c *' d) list here"

Thanks for any help!

+4
source share
3 answers

You can use many functions in the Collections.List module. Since F # does not have a break or a real return , 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 consists of two functions from the Collections.List module.

  • First we have a List.tryFind predicate list function that returns the first element for which this predicate function returns true .

    The result is obtained in the form of the option type, which can take two values: None and Some(x) . It is used for functions that sometimes do not give a useful result.

    Signature: tryFind : ('T -> bool) -> 'T list -> 'T option , where 'T is the type of the element, and ('T -> bool) is the type of the predicate function.

    In this case, it will search through the target list, looking for tuples where the first element ( y ) is equal to the variable x from the external function.

  • Then we have the List.pick mapper list function, which applies the mapper function to each of them, until the first result is returned, which is not None .

    This function will not return the value of option , but will instead throw an exception if the item is not found. There is also an option variant of this function called List.tryPick .

    Signature: pick : ('T -> 'U option) -> 'T list -> 'U , where 'T is the element type, 'U is the result type, and ('T -> 'U option) is the function type display.

    In this case, it will go through source -list, looking for matches in the target array (through List.tryFind ) for each of them and stop at the first match.


If you want to write loops explicitly, here is what it might look like:

 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 the usual ways to write lists or sequences of items)

+2
source

First, consider your code and annotate all types:

 let findInList source target = let itemFound = seq { for n in source do yield target |> List.filter (fun (x,y) -> x = n) } |> Seq.head itemFound 

The yield List.Filter ... means that you are creating a sequence of lists: seq<list<'a * 'b>> .

The Seq.head takes the first element from your list of lists: list<'a * 'b> .

Thus, the whole function returns list<'a * 'b> , which is clearly not suitable for your function. I think you intended to write something like this:

 let findInList source target = let itemFound = target // list<'a * 'b> |> List.filter (fun (x,y) -> x = n) // list<'a * 'b> |> Seq.head // 'a * 'b itemFound // function returns 'a * 'b 

There are many ways to get the desired results. Your code is halfway there. Instead of manually filtering, I recommend using the built-in val Seq.find : (a' -> bool) -> seq<'a> -> 'a method val Seq.find : (a' -> bool) -> seq<'a> -> 'a :

 let findAge l name = l |> Seq.find (fun (a, b) -> a = name) |> snd 

Or you can try using another data structure, such as Map<'key, 'value> :

 > let namesAndAges = [ ("john", 10); ("andrea", 15) ] |> Map.ofList;; val namesAndAges : Map<string,int> = map [("andrea", 15); ("john", 10)] > namesAndAges.["john"];; val it : int = 10 

If you want to write it manually, try this with a seq expression:

 let findInList source target = seq { for (x, y) in source do if x = target then yield y} |> Seq.head 
+3
source

Like fst use this (below). This way you can access all the values.

This is from F # interactive

 let a = ((1,2), (3,4)); let b = snd (fst a);; //interactive output below. val a : (int * int) * (int * int) = ((1, 2), (3, 4)) val b : int = 2 
0
source

Source: https://habr.com/ru/post/1333095/


All Articles