Guitardeon
Guitardeon

Reputation: 73

F# Adding to Lists not Taking Place

Hey guys I've been having a bit of trouble with my F# program. I basically have an unknown amount of size 12 lists of floats (handled by reading in the file and parsing) and I want to take these lists and split them into 12 lists respective to each elements. So for example I want all the 5th elements of my lists to go into n5 and so on. I have my list declarations as up in the top of my code

let (n1: float list) = []
let (n2: float list) = []
let (n3: float list) = []
let (n4: float list) = []
let (n5: float list) = []
let (n6: float list) = []
let (n7: float list) = []
let (n8: float list) = []
let (n9: float list) = []
let (n10: float list) = []
let (n11: float list) = []
let (n12: float list) = []

A recursive accessor as

let rec accsessline line = 
  if line = [] then
    ()  
   else      
     let (year, values) = ParseLine line.Head   
     (Pusher values)
     accsessline line.Tail

And a list filler method that called in the above code segment as (note my comment)

let Pusher (yearsFalls : float list)  =
    printfn "years falls are %f" yearsFalls.[6] //this line correctly accesses and prints the right element (6th) in each list yearsFalls.
    yearsFalls.[0] :: n1
    yearsFalls.[1] :: n2
    yearsFalls.[2] :: n3
    yearsFalls.[3] :: n4
    yearsFalls.[4] :: n5
    yearsFalls.[5] :: n6
    yearsFalls.[6] :: n7
    yearsFalls.[7] :: n8
    yearsFalls.[8] :: n9
    yearsFalls.[9] :: n10
    yearsFalls.[10] :: n11
    yearsFalls.[11] :: n12

Now everything works fine its only the part where I am trying to add to these lists that is not working. When I print out one of the n1-n12 lists after the above accessline function is called, the correct elements are access as shown in my output for the printfn that prints out the 6th element of each line (the only comment in my code), BUT the list prints out as empty brackets "[]". It's just the actual adding to the n1-n12 lists that is not taking place. Do you have an idea what I exactly I need to do to get the implementation working? Thanks for your time!

Upvotes: 0

Views: 118

Answers (2)

Fnugget
Fnugget

Reputation: 1

As Gene pointed out, you are working with immutable data structures so your n1..n12 lists will always be empty when referenced. Instead you need to accumulate the lists and then return a list of lists which you may then store. Alternatively when declaring each of the n1..n12 lists, you could find the elements for each list as they are declared.

A solution I made to distribute the elements of a presumed unknown number of lists of ints of length 12 in the manner you suggested:

// Some list to work on as input, read from your file for instance
let list = 
    [
        [1..12] 
        [1..12]
        [1..12]
        [1..12]
        [1..12]
        [1..12]
        [1..12]
        [1..12]
        [1..12]
    ]
let distributeElements inputList =
    // For each sublist of the inputList take out the appropriate element and add it to the list, then move on to the next sublist
    let rec gatherFromEachSubList (inputList: list<list<int>>) indexOfInput elementNumber accum =
        if indexOfInput < (inputList |> List.length) then 
            let newAccum = inputList.[indexOfInput].[elementNumber - 1] :: accum
            gatherFromEachSubList inputList (indexOfInput+1) elementNumber newAccum
        else 
            accum

    // For each category (n1..n12) gather from the sublists of the inputlist
    let rec gatherLists inputList elementNumber accum =
        if elementNumber > 0 then
            let newAccum = gatherFromEachSubList inputList 0 elementNumber List.empty :: accum
            gatherLists inputList (elementNumber - 1) newAccum
        else
            accum
    gatherLists inputList 12 List.empty

[<EntryPoint>]
let main argv =     
    let result = distributeElements list
    result |> List.map (fun a -> printfn "%A" a) |> ignore
    0 // return an integer exit code

And the results when run in FSI:

let result = distributeElements list
result |> List.map (fun a -> printfn "%A" a) |> ignore;;

[1; 1; 1; 1; 1; 1; 1; 1; 1]
[2; 2; 2; 2; 2; 2; 2; 2; 2]
[3; 3; 3; 3; 3; 3; 3; 3; 3]
[4; 4; 4; 4; 4; 4; 4; 4; 4]
[5; 5; 5; 5; 5; 5; 5; 5; 5]
[6; 6; 6; 6; 6; 6; 6; 6; 6]
[7; 7; 7; 7; 7; 7; 7; 7; 7]
[8; 8; 8; 8; 8; 8; 8; 8; 8]
[9; 9; 9; 9; 9; 9; 9; 9; 9]
[10; 10; 10; 10; 10; 10; 10; 10; 10]
[11; 11; 11; 11; 11; 11; 11; 11; 11]
[12; 12; 12; 12; 12; 12; 12; 12; 12]

Upvotes: 0

Gene Belitski
Gene Belitski

Reputation: 10350

You should realize that F# list is an immutable data structure, just as a simple experiment with FSI below demonstrates:

> let ll: int list = [];;
val ll : int list = []
> 1::ll;;
val it : int list = [1] // expression value is a new list
> ll;;
val it : int list = []  // ...but original list did not change ?!

In order to accumulate elements in a list at least two ways exist in F#:

  • non-idiomatic one of forcing the list to be mutable:

> let mutable ll: int list = [];;
val mutable ll : int list = []
> ll <- 1 :: ll;; // mutate list by prepending an element
val it : unit = ()
> ll;;
val it : int list = [1] // list has changed
  • idiomatic one of combining function applications:

> let prepend l ll = l :: ll;;
val prepend : l:'a -> ll:'a list -> 'a list
> [] |> prepend 1;;
val it : int list = [1]
> [] |> prepend 1 |> prepend 2;;
val it : int list = [2; 1]
........................

That said gives, perhaps, enough clues to implement your program non-idiomatically. For idiomatic solution considering the following solution of simpler, but similar problem may help: imagine you need to partition a list of integers putting odd elements into one list and even elements into the other. The following snippet will do:

>let rec partition (odds,evens) ll =
    match ll with
    | [] -> (odds,evens)
    | h::t -> match h % 2 with
              | 0 -> partition (odds, h :: evens) t
              | _ -> partition (h :: odds, evens) t;;

val partition :
  odds:int list * evens:int list -> ll:int list -> int list * int list

> partition ([],[]) [1;42;-3;7;14];;
val it : int list * int list = ([7; -3; 1], [14; 42])

Just grok how above works and apply a similar approach to your original problem. Good luck!

Upvotes: 2

Related Questions