如何将字符列表转换为字符串?

25
在F#中,我想将一个字符列表转换为字符串。考虑以下代码:

let lChars = ['a';'b';'c']
如果我只是简单地使用 lChars.ToString,我会得到 "['a';'b';'c']"。我想要得到的是 "abc"。我意识到我可能可以使用 List.reduce 实现我想要的效果,但似乎库中应该有一些原始的方法来实现这一点。
为了更好地理解这一点,我正在对字符串中的单个字符进行一些操作,完成后,我想显示结果字符串。
我已经尝试通过谷歌搜索解决这个问题,但没有找到答案。我是否需要咬紧牙关构建一个 List.reduce 表达式来执行这个转换,还是有更优雅的方法来实现这个目标?
7个回答

35

你尝试过吗?

System.String.Concat(Array.ofList(lChars))

12
new System.String(lchars |> Array.of_list) 也同样有效。 - Juliet
@JaredPar,谢谢!正合我意。我想必定有一些简单的方法可以获取我想要的字符串。@Juliet,你应该把它发布为答案 :-) 我会投票支持它,因为这也是一个很好的建议。 - Onorio Catenacci
8
如果您正在使用.NET 4或更高版本,则System.String.Concat(lChars)也可以完成此操作。 - Sean U
7
在 F# 4.0 中,let result = lChars |> Array.ofList |> String 也可以工作。 - ghord

9
你可以用多种方法在F#中构建字符串。 下面是另外几种方法:
let chars = ['H';'e';'l';'l';'o';',';' ';'w';'o';'r';'l';'d';'!']

//Using an array builder
let hw1 = new string [|for c in chars -> c|]

//StringBuilder-Lisp-like approach
open System.Text
let hw2 = 
    string (List.fold (fun (sb:StringBuilder) (c:char) -> sb.Append(c)) 
                      (new StringBuilder())
                       chars)

//Continuation passing style
let hw3 =
    let rec aux L k =
        match L with
        | [] -> k ""
        | h::t -> aux t (fun rest -> k (string h + rest) )
    aux chars id

编辑:时间可能很有趣?我将hw1..3转换成函数,并向它们提供了一个包含500000个随机字符的列表:

  • hw1:51毫秒
  • hw2:16毫秒
  • hw3:额...足够长,可以留胡子了吗?我想它刚刚吃掉了我的所有内存。

4

这里好像没有看到类似的内容,所以:

let stringFromCharList (cl : char list) =
    String.concat "" <| List.map string cl

""表示一个空字符串。

FSI输出:

> stringFromCharList ['a'..'d'];;
val it : string = "abcd"

编辑:

回来看这个语法,不太喜欢,所以这里提供一个更具有规范性的函数式语法:

['a'..'z'] |> List.map string |> List.reduce (+)

最新版本很好,但是它的复杂度与列表的大小成二次关系。 - enedil
嗯,我猜在大列表上你不太会用它。你怎么减少时间复杂度呢? - tykom

2
['a';'b';'c'] |> List.fold_left (fun acc c -> acc ^ (string c)) ""

编辑: 这是另一种有趣的完成任务的方法:
type t =
  | N
  | S of string
  static member Zero
    with get() = N
  static member (+) (a: t, b: t) = 
    match a,b with
      | S a, S b -> S (a+b)
      | N, _ -> b
      | _, N -> a

let string_of_t = function
  |N -> ""
  |S s -> s

let t_of_char c = S (string c)

['a'; 'b'; 'c'] |> List.map t_of_char |> List.sum |> string_of_t

遗憾的是,仅仅通过在System.String中添加“Zero”成员不能使List.sum与字符串一起使用。

编辑(回答Juilet): 是的,你说得对,左折叠确实很慢。但我知道更慢的是右折叠 :) :

#r "FSharp.PowerPack"

List.fold_right (String.make 1 >> (^)) ['a';'b';'c'] ""

当然,还有快速简单的解决方案:
new System.String(List.to_array ['1';'2';'3'])

1
@ssp,有一件事我尝试使用^运算符连接字符串,编译器警告我这可能与OCaml不兼容。它建议我使用+来连接字符串。 - Onorio Catenacci
3
fold_left很有趣,但你需要记住,字符串的追加操作是O(n),而逐个添加字符进行追加则是O(n^2)! - Juliet

1
以下解决方案适用于我:
let charList = ["H";"E";"L";"L";"O"]

let rec buildString list = 
    match list with
    | [] -> "" 
    | head::tail -> head + (buildString tail)

let resultBuildString = buildString charList

2
注意 - 这是字符串列表,而不是字符。另外,您刚刚重新实现了List.fold函数。 - John Palmer
这不是正确的答案,但它仍然很有用,谢谢。 - Petetheodddog

1
我使用了“sprintf”,对我来说更容易:
let t = "Not what you might expect"
let r = [ for i in "aeiou" -> i]
let q = [for a in t do if not (List.exists (fun x -> x=a) r) then yield a]
let rec m  = function  [] -> "" | h::t ->  (sprintf "%c" h) + (m t)
printfn "%A"  (m q)

1
大括号有什么作用? - Onorio Catenacci
我认为 let r = List.ofSeq "aeiou" 更简单。 - phoog

1
    [|'w'; 'i'; 'l'; 'l'|]
    |> Array.map string
    |> Array.reduce (+)

或者像其他人发布的一样:
    System.String.Concat([|'w'; 'i'; 'l'; 'l'|])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接