我希望你能用牛津(或串联)逗号将一组字符串合并为一个字符串。
给定:
这怎么能够改进呢?
--- 编辑 --- 关于多次迭代序列的评论是正确的。下面这两个实现都避免了转换为数组。
如果我使用“seq”,我非常喜欢这个:
这个也相当不错,甚至跳跃更少:
给定:
let ss = [ "a"; "b"; "c"; "d" ]
I want
"a, b, c, and d"
下面是我的想法。
let oxford (strings: seq<string>) =
let ss = Seq.toArray strings
match ss.Length with
| 0 -> ""
| 1 -> ss.[0]
| 2 -> sprintf "%s and %s" ss.[0] ss.[1]
| _ ->
let allButLast = ss.[0 .. ss.Length - 2]
let commaSeparated = System.String.Join(", ", allButLast)
sprintf "%s, and %s" commaSeparated (Seq.last ss)
这怎么能够改进呢?
--- 编辑 --- 关于多次迭代序列的评论是正确的。下面这两个实现都避免了转换为数组。
如果我使用“seq”,我非常喜欢这个:
open System.Linq
let oxfordSeq (ss: seq<string>) =
match ss.Count() with
| 0 -> ""
| 1 -> ss.First()
| 2 -> sprintf "%s and %s" (ss.ElementAt(0)) (ss.ElementAt(1))
| _ ->
let allButLast = ss.Take(ss.Count() - 1)
let commaSeparated = System.String.Join(", ", allButLast)
sprintf "%s, and %s" commaSeparated (ss.Last())
如果我使用array
,还可以利用索引避免对Last()
的迭代。
let oxfordArray (ss: string[]) =
match ss.Length with
| 0 -> ""
| 1 -> ss.[0]
| 2 -> sprintf "%s and %s" ss.[0] ss.[1]
| _ ->
let allButLast = ss.[0 .. ss.Length - 2]
let commaSeparated = System.String.Join(", ", allButLast)
sprintf "%s, and %s" commaSeparated (ss.[ss.Length - 1]
--- 编辑 ---
看到@CaringDev提供的链接,我认为这很不错。没有通配符,可以处理null值,在正确获取索引方面比较简单,并且Join()方法只需遍历数组一次。
let oxford = function
| null | [||] -> ""
| [| a |] -> a
| [| a; b |] -> sprintf "%s and %s" a b
| ss ->
let allButLast = System.ArraySegment(ss, 0, ss.Length - 1)
let sb = System.Text.StringBuilder()
System.String.Join(", ", allButLast) |> sb.Append |> ignore
", and " + ss.[ss.Length - 1] |> sb.Append |> ignore
string sb
这个也相当不错,甚至跳跃更少:
这个也相当不错,甚至跳跃更少:
let oxford2 = function
| null | [||] -> ""
| [| a |] -> a
| [| a; b |] -> sprintf "%s and %s" a b
| ss ->
let sb = System.Text.StringBuilder()
let action i (s: string) : unit =
if i < ss.Length - 1
then
sb.Append s |> ignore
sb.Append ", " |> ignore
else
sb.Append "and " |> ignore
sb.Append s |> ignore
Array.iteri action ss
string sb