Shiro Pie
Shiro Pie

Reputation: 223

F# filtering sublist

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

Upvotes: 2

Views: 169

Answers (2)

Jwosty
Jwosty

Reputation: 3634

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]

Upvotes: 1

Christophe
Christophe

Reputation: 73376

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    ]

Upvotes: 1

Related Questions