reggaeguitar
reggaeguitar

Reputation: 1804

Loop through list of 2 tuples to replace part of a string

I'm trying to replace chained String.Replace() calls with a more functional version. Original:

let ShortenRomanNumeral (num : string) : string = 
    num.Replace("VIIII", "IX").Replace("IIII", "IV").Replace("LXXXX", "XC").Replace("XXXX", "XL").Replace("DCCCC", "CM").Replace("CCCC", "CD")

Functional version that works with one key value pair:

let ShortenRomanNumeral' (str : string) (k : string) (v : string) : string =
    let strAfterReplace =
        str.Replace(k, v)
    strAfterReplace

I'm struggling to extend it to work with a list of tuples, such as

let replacements = [("VIIII", "IX"); ("IIII", "IV"); ...]

How can I write this function to apply the Replace() to the string for each key and value in the replacements list?

Upvotes: 1

Views: 202

Answers (2)

Grundoon
Grundoon

Reputation: 2764

Fold is good. But just to demonstrate another way to do it...

// You can put the input string 
// as the LAST parameter not first
let shortenRomanNumeral (k:string,v:string) (input:string)  =
    input.Replace(k,v)

// This allows you to do partial application like this
let replace4 = shortenRomanNumeral ("IIII", "IV")
let replace9 = shortenRomanNumeral ("VIIII", "IX")

// replace9 and replace4 have the signature string->string
// they are now simple string transformation functions
replace4 "abcIIIIdef" |> printfn "result is '%s'"
replace9 "abcVIIIIdef" |> printfn "result is '%s'"

// and they can be composed together.
// Order is important. Do 9 before 4.
let replace4and9 = replace9 >> replace4 

replace4and9 "VIIII abc IIII" |> printfn "result is '%s'" 

// With this approach, you can now transform a list of tuples 
// into a list of string transforms using List.map
let listOfTransforms = 
    [("VIIII", "IX"); ("IIII", "IV");] 
    |> List.map shortenRomanNumeral 

// and you can combine all these into one big transformation 
// function using composition
let transformAll = 
    listOfTransforms 
    |> List.reduce (>>)

// finally you can apply the big function
transformAll "VIIII abc IIII" |> printfn "result is '%s'" 

Upvotes: 3

Gus
Gus

Reputation: 26184

A fold will do the job:

let ShortenRomanNumeral' (str : string) (k : string, v : string) : string =
    let strAfterReplace =
        str.Replace(k, v)
    strAfterReplace

let replacements = [("VIIII", "IX"); ("IIII", "IV"); ]

let replaceValues str = List.fold ShortenRomanNumeral' str replacements

replaceValues "VI VII VIIII I II III IIII" // "VI VII IX I II III IV"

Note that I only modified the last parameter of ShortenRomanNumeral' to accept tupled values.

Upvotes: 2

Related Questions