SSOPLIF
SSOPLIF

Reputation: 321

Confused on accessing data in a list of tuples F#

//Return a tuple from a text file:
let ExtractFromLine (line:string) =
 let strings = line.Split('\t') //data members are spaced by tab
 let strlist = Array.toList(strings) //each data member is now a list of str
 let year = System.Int32.Parse(strlist.Head) //year is first in file, so Head
 let values = List.map System.Double.Parse strlist.Tail //tail are all values
 let average = List.average values //not part of text file
 let min = List.min values //not part of text file
 let max = List.max values //not part of text file
 (year, values, average, min, max) //return tuple with all info

//----------
let rec createList fileline =
 if fileline = [] then
  []
 else 
  let (year, values, average, min, max) = ExtractFromLine fileline.Head
  let l = (year, values, average, min, max) :: createList fileline.Tail
  l

//------------
let main argv =
 let file = ReadFile "data.txt"

 let biglist = createList file //recursive function to make a list of tuples
 printfn"%A" biglist //This prints the year, all values, average, min, and max for each tuple created

I now have a giant list of tuples with all of the information that I need. Have I retained the possibility of accessing all elements inside and performing calculations on them? I program in C++, and the solution is doable in that language, but F# is so much more powerful in my opinion. I'm sure its possible, I'm just missing the basics.

For example, how do I print the average of all the values for all years? I'm thinking of a for loop, but I'm not sure how to iterate.

for(all tuples in biglist)
printfn"%A:%A" tuple.year tuple.average

It's wrong obviously, but I think you guys understand what I'm trying to do.

The above question involves pulling data from one tuple at a time across the list. What if I wanted to print the largest average?This would involve accessing each tuple's average data member and comparing them to return the largest one. Do I have to create another list containing these averages?

I learned about fst and snd but I had a hard time applying it to this example. You don't have to answer all questions if it is too much, but any help is greatly appreciated as I start out in this language, thank you

Upvotes: 0

Views: 3194

Answers (2)

PiotrWolkowski
PiotrWolkowski

Reputation: 8782

You can loop in F# but it's a construct from imperative programming world. More idiomatic approach is to access items of the list recursively.

Below some sample code that creates tuples, constructs a list, and then access items and checks which one is bigger. Looking at your code the average was third item in the tuple. That's why I've added a trd function. It takes a 5-item tuple and returns a third item.

The prcsLst function takes 2 arguments: a list and a starting max value. The idea is that when processing the list we take the head (first item on the list), compare it's average with current max. Whichever is bigger is passed to the next recursive round together with list's tail (the list without the first item).In this case as the initial max I passed in the average of the first item.

You can run the example in F# Interactive to see the results.

// create sample tuples
let t1 = (2014, 35, 18, 5, 45)
let t2 = (2014, 32, 28, 8, 75)
let t3 = (2014, 25, 11, 9, 55)
let t4 = (2015, 16, 13, 2, 15)
let t5 = (2015, 29, 15, 1, 35)

// create sample list
let lst = [t1;t2;t3;t4;t5]

// a function to return third item in a tuple
let trd (_,_,t,_,_) = t

// process list recursively
let rec prcsLst l max =
    match l with
    | [] -> max
    | hd::tl ->
        if (trd hd) > max then
            prcsLst tl (trd hd)
        else
            prcsLst tl max


// invoke the method on the sample list
// as a starting point use the first item in the list
prcsLst lst (trd t1);;

Upvotes: 3

Benjol
Benjol

Reputation: 66587

On a mobile so forgive me for not doing any code examples :)

I suspect that the missing piece of your puzzle is called pattern matching. In F# you address elements of a tuple like so:

let (y, v, Av, mn, mx) = mytuple

Note that you can also use this in function declarations, and when doing a 'match'.

(there is an exception for 'twoples' where you can use the functions 'fst' and 'snd')

Another thing you should play with is the |> operator.

Upvotes: 1

Related Questions