Reputation: 157
Code:
let studentMap =
for i = 0 to count do
Map.empty.Add(students.[i].getId(), students.[i].getScores())
I am trying to add to a map sequentially. I have student objects in an array and am trying to add them in order. I am confused at how to do this. I thought maybe you make an empty map then add to it in order via a for loop, but it always causes trouble and won't work. Is there a way to add items to a map using a for loop? The <key/value>
pairs are this: <string, int array>
. That is the way I want it formatted but it keeps giving me trouble. I'll restate the goal again to clarify: I want to be able to add items to a map using a for loop with my student objects array being used to get the appropriate data I need in there. I will be able to give it a string and get back that student's grades for example. I know it's a weird problem I'm working on, but I needed to try something simple at first.
Upvotes: 5
Views: 4764
Reputation: 14468
In functional languages, the built-in data structures are immutable, that is, when you add an element, a new value of the data structure is returned.
If you want to convert one structure to another, you can often use one of the build-in functions like Map.ofArray
. If you have a more complex scenario, like a function generating your values, then you can use a 'loop', and each iteration of the loop returns a new value of the data structure. The way to express such a 'loop' in a functional way, is to use a recursive function:
let studentMap =
let rec loop currentMap i =
if i >= count then currentMap
else
let newMap = Map.add (students.[i].getId()) (students.[i].getScores()) currentMap
loop newMap (i+1)
loop Map.empty 0
Now you have full flexibility in how you generate the values (they don't have to be part of an array) and you're avoiding mutable variables that are un-idiomatic in functional programming. Ideally, like in this case, the function should be tail-recursive to allow tail-call optimisation (and avoid stack overflow for large inputs).
Upvotes: 2
Reputation: 751
I think the Map.ofArray approach is probably the best, but it is worthwhile to point out that the for loops can done a bit better:
let map = new System.Collections.Generic.Dictionary<int, Scores>()
for student in students do
map.Add(student.getId(), student.getScore())
This neatly avoids making array bounds mistakes.
Upvotes: 2
Reputation: 144136
You could use a mutable map variable:
let studentMap =
let mutable m <- Map.empty
for i = 0 to count do
m <- m.Add(students.[i].getId(), students.[i].getScores())
m
or a mutable dictionary:
let studentMap =
let m = new System.Collections.Generic.Dictionary<int, Scores>()
for i = 0 to count do
m.Add(students.[i].getId(), students.[i].getScores())
m
a more functional solution would be to use a fold:
let studentMap = seq { 0 .. count } |> Seq.fold (fun (m: Map<int, Scores>) i -> m.Add(students.[i].getId(), students.[i].getScores())) Map.empty
Upvotes: 4
Reputation: 2551
You can try a more functional idiomatic approach:
Let's say you have an array of type Student
(in the example below is an empty array):
let students = Array.empty<Student>
You can transform your array in to a Map
:
let mapStudents = students
|> Array.map (fun s -> (s.getId(), s.getScore()))
|> Map.ofArray
Upvotes: 10