2
votes

I am struggling to write a function where it takes a Sequence, say Hand= {C2; H8; DK; S1} and finds the the lowest integer outcome by 1st removing an element, then using a function I have named CalculateScore() to find the score of that new Sequence. It does this for all elements in the Sequence but only removes that 1 element, not the ones before it, so 1st run it will remove C2 and calculate score, then it will remove H8(not removing C2) and calculate score. Once it has calculated all scores it then needs to find the one with the lowest value and return that element.

Here is a very brute force non-F# pseudo code example of what I am referring to:

Hand= {C2; H8; DK; S1}, i = 0
NewHand = Hand[i].remove
Score = CalculateScore(newHand)
elementIndex = i
i++
NewHand = Hand[i].remove
if Score > CalculateScore(NewHand) 
    then Score = NewHand, elementIndex = i
i++
.........
return elementIndex

I have not been doing F# for very long and I am not very good at creating high order functions and stuff like that which is why I am struggling.

1
Look in to Seq.minBy - John Palmer
How would I go about removing an element from the Sequence? There doesn't seem to be a simple way. - TJ8
@Foggy Finder Say I have a hand of 10 cards, I need to find the best card to discard by 1st testing my score after discarding each card so find which one gives the lowest score(goal is to get as close to or get 0 as your score). Which is why I want to remove an element from the sequence so I can test the score and do this for each element. - TJ8

1 Answers

4
votes

When you're having problems with higher order functions and how to compose them, it usually helps to start with writing down the transformation you wish to apply.

let calcScoreAfterRemovingElement s el =
    s
    |> Seq.filter ((<>) el)
    |> calcScore

Here we remove an element from the sequence and then calculate the score.

Now, to apply this transformation to each element in the list and calc the minimum, we can simply:

Seq.minBy (calcScoreAfterRemovingElement s) s

Which is shorthand for:

Seq.minBy (fun el -> calcScoreAfterRemovingElement s el) s

As we map the elements => to the filtered sequences => to their corresponding values and return the minimum.

For example, if we used a calcCard function instead of calcScore, we could then:

let calcScoreAfterRemovingElement s el =
    s
    |> Seq.filter ((<>) el)
    |> Seq.sumBy calcCard

Here you remove the (current) element, map the elements of the filtered sequence to their corresponding values and sum them.

EDIT

You could get the index using Seq.findIndex or Seq.tryFindIndex, but that would break the pipeline. Let's try a different approach:

Seq.minBy (calcScoreAfterRemovingElement s) s

=

s
|> Seq.map (calcScoreAfterRemovingElement s)
|> Seq.min

Fetching the index

s
|> Seq.map (calcScoreAfterRemovingElement s)
|> Seq.indexed
|> Seq.minBy snd
|> fst

=

s
|> Seq.mapi (fun i el -> i , calcScoreAfterRemovingElement s el)
|> Seq.minBy snd
|> fst