Here is an input list: [[10;2;10]; [10;50;10]; [10;1;10]].
How would I filter the second element of each sub-list?
Below is my code and when I output the result I get [[10;50;10]] but what I want is [2;50;1]. Is there anyway to fix my code? I am really trying to understand F#. Thanks for the help in advance.
let sub =
let input = [[10;2;10]; [10;50;10]; [10;1;10]]
let findIndex input elem = input |> List.findIndex ((=) elem)
let q = input |> List.filter(fun elem -> findIndex input elem = 1)
printfn "%A" q
The following will get the expected result:
let second (x:List<int>) = x.[1]
let q = List.map second input
List.map is a higher order function that makes a new list by applying a function (the first argument, here the function second that returns the second element of a list) to a list (here input):
[ [10;2;10]; [10;50;10]; [10;1;10] ]
| | |
second second second <--- mapping function
| | |
V V V
[ 2 ; 50 ; 1 ]
Use List.map, not List.filter
List.filter keeps/removes items from an input list based on the function you give it, e.g. List.filter (fun x -> x % 2 = 0) myList would keep only the even numbers in myList. You can get an idea of this functionality based on its type signature, which is val filter: ('a -> bool) -> 'a list -> 'a list, meaning it takes a function (that takes an 'a and returns a boolean: ('a -> bool)), then takes a list, and returns a list of the same type.
List.map, on the other hand, transforms each element of a list into whatever you want, based on a function you give it. In your case you would use it like so:
let input = [[10;2;10]; [10;50;10]; [10;1;10]]
let result = input |> List.map (fun numbers -> numbers.[1])
printfn "%A" result
The signature of List.map is val map: ('a -> 'b) -> 'a list -> 'b list, meaning it takes a function that maps 'as to 'bs (in your case, this would map int lists to ints), takes a list of the first thing, and returns a list of the second thing.
Use List.map and List.tryIndex
Note that if any of the sub-lists are too short, the program will crash. If this is a concern, you can use a safe version of myList.[i]; namely List.tryIndex, which returns None if the item was not found. Try this out:
// Note the last sublist
let input = [[10;2;10]; [10;50;10]; [10;1;10]; [-1]]
let result : int option list = input |> List.map (fun numbers -> List.tryIndex 1 numbers)
printfn "%A" result
// This prints:
// [Some 2; Some 50; Some 1; None]
Related
I have created a working solution for concat, but I feel that I can reduce this using List.fold_lift.
Here is my current code:
let rec concat (lists : 'a list list) : 'a list =
match lists with
| [] -> []
| hd :: tl -> hd # concat tl ;;
Here is what I have tried:
let concat (lists : 'a list list) : 'a list =
List.fold_left # lists ;;
This gives me the error: This expression has type 'a list list but an expression was expected of type
'a list
I think this is because the return value of list.fold_left gives us a list, but we are feeding it a list of lists so it then returns a list of lists again. How can I get around this without matching?
I was also playing around with List.map but with no luck so far:
let concat (lists : 'a list list) : 'a list =
List.map (fun x -> List.fold_left # x) lists ;;
Consider the type signature of List.fold_left:
('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
List.fold_left takes three arguments.
A function.
An initial value.
A list to iterate over.
List.fold_left # lists
You're making two mistakes.
First off, this parses as (List.fold_left) # (lists).
You're looking for List.fold_left (#) lists. But that's still not quite right, because...
You're only passing two arguments, with lists being the initial value, while List.fold_left expects three.
I think that you're looking for something like:
let concat lists = List.fold_left (#) [] lists
Demonstrated:
utop # let concat lists = List.fold_left (#) [] lists in
concat [[1;2;3]; [4;5;6]; [7;8;9]];;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]
It is possible to write concat as fold_left while avoiding quadractic complexity by switching temporarily to different representation of list
If I have a list l, I can easily lift into an append function:
let to_append l = fun new_list -> l # new_list
I can also get back a list from an append function with
let to_list append = append []
And since for any list l, I have to_list ## to_append l = l, this means that the to_append is one-to-one: it does not lose any information.
Moreover concatenating two appends functions is exactly function composition
let append_concat f g l = f (g l)
Since we are not building yet any concrete list, append_concat has a constant cost (we are delaying the time complexity to the moment where we will call the append function).
We can use this better behavior of append_concat to write a linear concat' function that maps a list of lists to an append function:
let concat' l =
List.fold_left
(fun append l -> append_concat append (to_append l))
(to_append [] (* aka Fun.id *))
l
Note that this concat' is not yet building a list, it is building a closure which records the list of append functions to call later.
Building concat from concat' is then a matter of transforming back my append function to a list:
let concat l = to_list (concat' l)
And it is the call of to_list which will have a time complexity equal to the size of the final list.
To check that we got the right complexity, we can test that flattening the following list
let test =
List.init 1_000_000
(fun i ->
List.init 4 (fun k -> k + 4 * i)
)
(* this is [[0;1;2;3]; [4;5;6;7]; ... [...; 3_999_999]] *)
with
let flattened = concat test
is nearly instant.
I am trying to write a function that filters positive integers from a list of list of integers, returning a list of only negative integers.
For example, if I have a list of list such as [[-1; 1]; [1]; [-1;-1]] it would return [[-1]; []; [-1;-1]].
I tried to use filter and transform functions, which was in my textbook.
let rec transform (f:'a -> 'b) (l:'a list) : 'b list =
begin match l with
| [] -> []
| x::tl -> (f x)::(transform f tl)
end
and for filter, I had previously written:
let rec filter (pred: 'a -> bool) (l: 'a list) : 'a list =
begin match l with
| [] -> []
| x :: tl -> if pred x then x :: (filter pred tl) else filter pred tl
end
So, using these, I wrote
let filter_negatives (l: int list list) : int list list =
transform (fun l -> (filter(fun i -> i<0)) + l) [] l
but I'm still having trouble fully understanding anonymous functions, and I'm getting error messages which I don't know what to make of.
This function has type ('a -> 'b) -> 'a list -> 'b list
It is applied to too many arguments; maybe you forgot a `;'.
(For what it's worth this transform function is more commonly called map.)
The error message is telling you a simple, true fact. The transform function takes two arguments: a function and a list. You're giving it 3 arguments. So something must be wrong.
The transformation you want to happen to each element of the list is a filtering. So, if you remove the + (which really doesn't make any sense) from your transforming function you have something very close to what you want.
Possibly you just need to remove the [] from the arguments of transform. It's not clear (to me) why it's there.
let sample_table4 = [
[["11"];["21"];["31"];["41"]];
[["12"];["22"];["32"]];
[["13"];["23"]];
[["14"]]];;
This is where I'm stuck with writing a function to get one of these numbers
let tgvc (pos, table) =
match pos with
|[] -> []
|i::[j] -> List.nth (List.nth table (j-1)) (i-1)
|i::_ -> []
;;
val tgvc : int list * 'a list list list -> 'a list = <fun>
I'm supposed to get this signature
tgvc ([3;2],sample_table4);;
val tgvc : int list * ’a list list -> ’a = <fun>
-: string list = ["32"]
What's missing in the function?
I'm sure it has to be recursive now.
Even though it computes the right answer, it's not the right method. The ->[ ] is what's getting me
let rec tgvc (pos, table) = function
|_,[] -> []
|[i;1], h::_ -> List.nth h (i-1)
|[i;j], _::t -> tgvc ([i;j-1], t)
|_ -> []
|[i;j], _::t -> tgvc ([i;j-1], t)
^^^^^^^^^^^^^^^^^
Error: This expression has type int list * 'a list list list -> 'a list
but an expression was expected of type 'a list
What's missing in the function?
A lot of things. Your function simply returns one of many lists of initial input. You don't even use i indice.
I suggest you to think what your function need to do for the given input:
[i; 1], h::_ - you are "in front" of the desirable list
[i; j], _::t - not desirable list yet (some recursion maybe?)
_, [] - empty table
_ - everything else
Edit
You have two problems with your last implementation. First of all in your first and last branches you return [], I guess you would like to exit with an error, so you can throw an exception (via failwith for example). The second problem is actually in the first line: get_table_values_cell (pos, table) = function, it means that you define get_table_values_cell as function with two arguments, you give one explicitly ((pos, table)) and the second is introduced by function keyword. So all you need is to pick only one: get_table_values_cell = function
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!
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)
First let's look at your code and annotate all the 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 statement yield List.Filter ... means you're creating a sequence of lists: seq<list<'a * 'b>>.
The statement Seq.head takes the first element from your sequence of lists: list<'a * 'b>.
So the whole function returns a list<'a * 'b>, which is obviously not the right type 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 lots of ways you can get the results you want. Your code is already half way there. In place of filtering by hand, I recommend using the built in val Seq.find : (a' -> bool) -> seq<'a> -> 'a method:
let findAge l name = l |> Seq.find (fun (a, b) -> a = name) |> snd
Or you can try using a different data structure like a 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 by hand, then try this with your seq expression:
let findInList source target =
seq {
for (x, y) in source do
if x = target then
yield y}
|> Seq.head
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
is there a way to iterate list over the list through List.map?
I know List.map takes single function and list and produce a list that the function applies to all elements. But what if i have a list of function to apply a list and produce list of the list ?
Your question is not very clear, however as far as I understand it, you have a list of functions and a list of values. If you want to apply all functions to all elements then you can write this:
(* // To get one nested list (of results of all functions) for each element *)
List.map (fun element ->
List.map (fun f -> f element) functions) inputs
(* // To get one nested list (of results for all elements) for each function *)
List.map (fun f ->
List.map (fun element -> f element) inputs) functions
In case this is not what you wanted, could you try clarifying the question a little bit (perhaps some concrete example would help)?
Are you allowed to use List.map2? Because then this is simple:
let lista = [(fun x -> x + 1); (fun x -> x + 2); (fun x -> x + 3)];;
let listb = [1; 1; 1];;
let listc = List.map2 (fun a b -> (a b)) lista listb;;
The output would be [2; 3; 4]
Edit: wait, I think I read your problem wrong. You want to get a list of lists, where each list contains a list of a function applied to the initial list? In other words, for the lista and listb above, you'd get:
[[2;2;2];[3;3;3];[4;4;4]]
Is this correct?
You can try this :
let rec fmap fct_list list = match fct_list with
[] -> //you do nothing or raise sth
head::tail -> List.map head list :: fmap tail list;;