3

I am trying to write a module in F# that will delete every 3rd element from a list and will return a new list without that elements.

for example

let  input = [ 1 .. 15 ] 

printfn "List with elements eliminated: %A" (Program1.remove input)

which sould give this output

List with elements eliminated: [1; 2; 4; 5; 7; 8; 10; 11; 13; 14] 

What i tried so far

module Program1 =
 open System
 let remove list1=
    let collectList = List.iteri (fun i x -> if i%3 <> 0 then   x) list1
    collectList
[<EntryPoint>]
let main argv =
 let list = [ 1; 2; 3] 
 printfn "new List is %A" (Program1.remove list )
 0

Now i am recieving an error and i tried all day to solve it. Thank you in advance

Joel Mueller
  • 28,324
  • 9
  • 63
  • 88

2 Answers2

1

For this error:

 error FS0001: Type mismatch. Expecting a
    'unit list'
but given a
    'int list'
The type 'unit' does not match the type 'int'

the problem comes from the line if i%3 <> 0 then x. It is an if-expression without an else clause, and it must have type of unit, and type inference results in x being type unit. For more details about F# conditionals, read https://learn.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/conditional-expressions-if-then-else.

EDIT: Also, List.iteri doesn't do what you intend to do because List.iteri doesn't return a list, it return a unit. You need functions such as List.map, List.filter, List.choose, List.foldBack to solve your problem.

Read the accepted answer from this post to get an idea about how to approach this problem (you will need to make minor modifications): Getting every nth Element of a Sequence

There is also a simpler approach using List.foldBack to build to resulting list.

Community
  • 1
  • 1
Ming-Tang
  • 17,410
  • 8
  • 38
  • 76
  • Maybe add a bit about the fact that `List.iteri` also returns `unit`. Also although the linked answer is correct a simpler approach can be done here (and there too) simply using `List.foldBack` – Sehnsucht Oct 09 '16 at 21:33
  • `let list = [ 1..15]` `let r1 = List.filter (fun x -> x % 3 <> 0) list` `printfn "new List is %A" r1` This was my final solution. Thank you for the hints. My problem was that i was trying to remove every trird element for every type of list but in my case, i will allways have an ascending ordered list so it can be easy done with List.filter. Thank you – Eduard Cantoriu Oct 10 '16 at 05:09
0

I am not sure if you trying to filter every third value or every value divideable by 3.

If its the first case than one functional approach could be like this

//safe take and skip fn (no exceptions)
let take x xs = if List.length xs >= x then List.take x xs else [] 
let skip x xs = if List.length xs >= x then List.skip x xs else []
let rec remove x xs =
    //effectively this drops every xnt element
    let head = take (x - 1) xs
    let tail = skip x xs
    match tail with
    | [] -> head
    | _  -> List.append head (remove x tail)

let x = ["One";"Two";"Three";"Four";"Five";"Six";"Seven";"Eight";"Nine";"Ten"]
remove 3 x

However this is pretty heavy weight ;-)
So a better approach might be as you have almost found

let x = ["One";"Two";"Three";"Four";"Five";"Six";"Seven";"Eight";"Nine";"Ten"]
let indices = [1 .. List.length x]

List.zip indices x 
|> List.filter (fun (x,_) -> x % 3 <> 0)
robkuz
  • 9,488
  • 5
  • 29
  • 50
  • 2
    Don't forget to only get the items in the end and since F#4.0 there is `List.indexed` which returns a list of item tupled with their indexes do you can rewrite it `x |> List.indexed |> List.filter (fun (i, _) -> i % 3 <> 0) |> List.map snd` – Sehnsucht Oct 10 '16 at 12:17
  • @Sehnsucht yeah thats even better – robkuz Oct 10 '16 at 21:16