【发布时间】:2019-04-10 03:43:18
【问题描述】:
我想使用牛津(或串行)逗号将一组字符串连接成一个字符串。
给定
let ss = [ "a"; "b"; "c"; "d" ]
我想要
"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
【问题讨论】:
-
有什么需要改进的地方?
-
我想知道是否有一些不必要的字符串分配,或者它是否可以更具可读性。
-
我也想知道是否有更好的方法来获取allButLast。
-
这更适合Code Review
标签: .net string collections f#