3

I'm positive that there is a better way to swap items in a list by pairs ( [1;2;3;4] -> [2;1;4;3] ) as I'm doing too many appends for my liking but I'm not sure how best to do it.

let swapItems lst =
    let f acc item =
        match acc with
        | [] -> [item]
        | hd :: next :: tl when tl <> [] -> [next] @ tl @ [item;hd]
        | _ -> item :: acc
    List.fold f [] lst

How can I improve this? This only works on lists that have an even length.

jscs
  • 63,694
  • 13
  • 151
  • 195
Dylan
  • 1,306
  • 1
  • 11
  • 29

3 Answers3

3

Simplest possible solution:

let rec swapItems = function
  | a::b::xs -> b::a::swapItems xs
  | xs -> xs

I like to make the names of variables that are sequences like lists "plural", e.g. xs instead of x.

Note that this is not tail recursive so it will stack overflow if you give it a very long list.

J D
  • 48,105
  • 13
  • 171
  • 274
2

What about this:

let rec swapItems = function
    | []
    | _::[] as l -> l
    | a::b::t ->
        b::a::(swapItems t)

?

Ramon Snir
  • 7,520
  • 3
  • 43
  • 61
  • 3
    I think doing it this way is slightly more elegant `function |a::b::t -> b::a::t |a -> failwith "not enough elements"` – John Palmer Sep 18 '11 at 22:51
  • brillant thanks, and curses to F# for always making things so simple ;) – Dylan Sep 18 '11 at 23:10
  • @jpalmer, I don't know why he is doing this, but I presumed he also wanted this solution to work for lists of odd number of elements. – Ramon Snir Sep 19 '11 at 06:40
  • @Ramon - I didn't realise that he also reorderd `4,3` as well - my solution doesn't work, although you can still combine the first two cases in your function if you move them to the end – John Palmer Sep 19 '11 at 06:59
  • @jpalmer, yes, it is a matter of style. I try to refrain from using a final-clause match cases. – Ramon Snir Sep 19 '11 at 07:04
  • You can shorten it if you make the last case first: `let rec swapItems = function a::b::t -> b::a::(swapItems t) | l -> l` – Daniel Sep 19 '11 at 14:06
  • @Daniel, that's what jpalmer suggested. – Ramon Snir Sep 19 '11 at 14:11
  • Sorry, I didn't read his comment closely enough. I saw `failwith` and assumed it's different. I guess that remains one slight difference from his. – Daniel Sep 19 '11 at 14:14
1

Using higher order functions this can be done as:

let swapItems l =
    l |> List.toSeq |> Seq.pairwise
    |> Seq.mapi (fun i (a,b) -> if i % 2 = 0 then seq [b;a] else Seq.empty)
    |> Seq.concat |> Seq.toList
Ankur
  • 33,367
  • 2
  • 46
  • 72
  • 1
    A list is a seq, you don't have to call ``List.toSeq``. I'm not sure it even does something (more than forcing the type-checker). – Ramon Snir Sep 20 '11 at 08:47