# Swap even/odd characters

I wrote some code to solve this problem https://www.hackerrank.com/challenges/string-o-permute which basically states: take an even length string and swap all the even indexed characters. For example the string "abcd" should become "badc". I'm looking for a general code review as I'm very new to F# and specifically I'd really like to get rid of the ignoredTupleValue variable, it seems like a kludge to me. I'd also like to collapse the whole thing into one function but I was running into scoping issues with the StringBuilder.

open System
open System.Text

[<EntryPoint>]
let main argv =
let numCases = Console.ReadLine() |> int
for i = numCases downto 1 do
let strIn = Console.ReadLine()
let pairs = Seq.pairwise strIn
let ignoredTupleValue = ('1', '1')
let swappedTuples = pairs |> Seq.mapi (fun idx pair ->
if idx % 2 = 0 then
let (a, b) = pair
(b, a)
else
ignoredTupleValue)
let answer = Seq.fold (fun (sb : StringBuilder) pair ->
if pair <> ignoredTupleValue then
let (a, b) = pair
sb.Append(a) |> ignore
sb.Append(b) |> ignore
sb)
(new StringBuilder())
swappedTuples
0

• There are many ways to do this problem, but if you're interested in removing ignoredTupleValue , think about using Seq.filter(...) – Ray May 27 '16 at 20:16
• I changed the title to describe the task the code accomplishes, this makes contrnt morr easily searchable and accesible. – Caridorc Jul 8 '16 at 14:38

Building off Caridorc's pseudocode, this function would do it:

let switchOddAndEven (str : string) =
str.ToCharArray()
|> Array.chunkBySize 2
|> Array.map Array.rev
|> Array.concat
|> System.String.Concat


The first and last methods are just switching between a char array and a string. Usage is simply:

switchOddAndEven "abcd";;
// val it : string = "badc"


or in your main method

[<EntryPoint>]
let main argv =
let numCases = Console.ReadLine() |> int
for i = numCases downto 1 do
|> switchOddAndEven
|> printfn "%s"
0


Note you don't need a full blown console app to do these kind of things. Create a new fsx file in Visual Studio (File -> New -> File -> F# Script File) then type your functions there. To execute just select it all and send it to the F# Interactive with Alt + Enter.

Edit

From the comments: one could take advantage of the fact that string is an IEnumerable and use the Seq module, which saves one method call:

let switchOddAndEven (str : string) =
str
|> Seq.chunkBySize 2
|> Seq.map Seq.rev
|> Seq.concat
|> System.String.Concat

• I'll give you the bounty if you change the name of the function to something descriptive, I hate names with "my" in them – reggaeguitar Jul 8 '16 at 17:21
• Heh. Changed it. What's in a name. – asibahi Jul 8 '16 at 17:22
• Everything is in a name :) – reggaeguitar Jul 8 '16 at 18:05
• Good that F# has all the necessary built-ins including chunks_of . I just think that strings should be a kind a list (strings subset_of lists) to avoid this back & forth conversion, but the designers of the language chose them to be different and there is no going back. – Caridorc Jul 9 '16 at 14:10
• @Caridorc that's likely more of a side effect of being built on top of the CLR more than a decision made by the F# team. – RubberDuck Jul 9 '16 at 16:13

The solution should look like (pseudocode, I know little F# too ;) ):

String
|> ChunksOf 2
|> Map Reverse
|> Flatten


An example explains clearly

"abcd" -> ["ab", "cd"] -> ["ba", "dc"] -> "badc"


The key of effective Functional Programming is making good use of the built-in functions and carefully combining them.

I'm not very good at F#, but anytime I see a for or a do (i.e. a loop) I cringe a little bit. It's more idiomatic to use Seq.Map to apply a function to each element of the range [numCases..1]. Which, since it's descending, you need to apply the step: [numCases..-1..1].

You could use Printf.bprintf to easily use a StringBuilder.

You could also use pattern matching to extract your length 2 array easily
(it'll cost you a warning for not handling every case but you [as a developer] know for sure it'll have a length of 2 because of the chunkBySize)

#nowarn "25" // to not see the aforementioned warning

let permuteEvenOdd str =
let builder = StringBuilder (String.length str)
let bprint format = Printf.bprintf builder format // helper to ease readability

str
|> Seq.chunkBySize 2
|> Seq.iter (fun [| c1; c2 |] -> bprintf "%c%c" c2 c1)

string builder


## Edit

As another alternative you can use Seq.permute
(as it's documentation is not yet available I give List.permute documentation instead, the behaviour is the same)

let permuteEvenOdd str =
str
|> Seq.permute (fun index -> index + if index % 2 = 0 then 1 else -1)
// |> Seq.permute (fun index -> -2 * (index % 2) + 1) // alternate version ; harder to understand
|> Seq.fold (sprintf "%s%c") "" // we could reuse bprintf here instead