Reputation: 73
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
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
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#:
> 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
> 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