F#String Of String:连接值

时间:2014-03-08 14:13:25

标签: f#

我有一个这样的数组:

let items = ["A";"B";"C";"D"]

我想把它转换成这样的数组:

let result = ["AB";"AC";"AD";"BC";"BD";"CD"]

我在语言规范中找不到任何内容 - 尽管我可能搜索不正确。我想到了Seq.Fold这样:

let result = items |> Seq.fold(fun acc x -> acc+x) ""

但我得到了"ABCD"

有谁知道怎么做?修改后的CartesianProduct会有效吗?

提前致谢

6 个答案:

答案 0 :(得分:3)

你有的是列表,而不是数组 - 列表使用[...]语法,数组使用[|...|]语法。

那就是说,这是一个简单的实现:

let listProduct (items : string list) =
    items
    |> List.collect (fun x ->
        items
        |> List.choose (fun y ->
            if x < y then Some (x + y)
            else None))

如果你把它放入F#interactive:

> let items = ["A"; "B"; "C"; "D"];;

val items : string list = ["A"; "B"; "C"; "D"]

> items |> listProduct |> Seq.toList;;
val it : string list = ["AB"; "AC"; "AD"; "BC"; "BD"; "CD"]

答案 1 :(得分:2)

这样的事情应该这样做:

items
|> List.map (fun x -> items |> List.map (fun y -> (x, y)))
|> List.concat
|> List.filter (fun (x, y) -> x < y)
|> List.map (fun (x, y) -> x + y)
|> List.sort

我不知道它是否对大型列表有效,但它确实产生了这个输出:

["AB"; "AC"; "AD"; "BC"; "BD"; "CD"]

<强>击穿

第一步通过两次映射items生成元组列表列表:

[[("A", "A"); ("A", "B"); ("A", "C"); ("A", "D")];
 [("B", "A"); ("B", "B"); ("B", "C"); ("B", "D")];
 [("C", "A"); ("C", "B"); ("C", "C"); ("C", "D")];
 [("D", "A"); ("D", "B"); ("D", "C"); ("D", "D")]]

其次,List.concat将列表列表转换为单个列表:

[("A", "A"); ("A", "B"); ("A", "C"); ("A", "D"); ("B", "A"); ("B", "B");
 ("B", "C"); ("B", "D"); ("C", "A"); ("C", "B"); ("C", "C"); ("C", "D");
 ("D", "A"); ("D", "B"); ("D", "C"); ("D", "D")]

第三,List.filter删除第一个元素等于或大于第二个元素的元组:

[("A", "B"); ("A", "C"); ("A", "D"); ("B", "C"); ("B", "D"); ("C", "D")]

第四,List.map生成一个连接字符串列表:

["AB"; "AC"; "AD"; "BC"; "BD"; "CD"]

最后,List.sort对列表进行排序,但在这种情况下没有必要,因为列表已经有正确的顺序。

您可能还会考虑使用Seq.distinct删除重复项(如果有的话)。

答案 2 :(得分:1)

您可以创建一个函数来创建列表中所有头/尾对的列表:

let rec dec = function
| [] -> []
| (x::xs) -> (x, xs) :: dec xs

或尾递归版:

let dec l =
    let rec aux acc = function
        | [] -> acc
        | (x::xs) -> aux ((x, xs)::acc) xs

    aux [] l |> List.rev

然后您可以使用此功能创建列表:

let strs (l: string list) = l |> dec |> List.collect (fun (h, t) -> List.map ((+)h) t)

答案 3 :(得分:1)

我会这样做:

let rec loop = function 
    [] -> []
  | x :: xs -> List.map ((^) x) xs @ loop xs

这样做的好处是不会从列表中构建每对元素只丢弃一半。 (我将把这个附加物除掉作为练习: - )

对我而言,与其他一些提议的解决方案相比,它更容易分辨出这里发生了什么。对于这类问题,在处理元素x的位置,您还需要访问列表xs的其余部分,标准组合器并不总能使解决方案更清晰。

答案 4 :(得分:1)

let items = ["A";"B";"C";"D"]
let rec produce (l: string list) =
    match l with
    // if current list is empty or contains one element - return empty list
    | [] | [_] -> [] 
    // if current list is not empty - match x to head and xs to tail
    | x::xs -> 
        [
            // (1) 
            // iterate over the tail, return string concatenation of head and every item in tail 
            for c in xs -> x + c 
            // apply produce to tail, concat return values
            yield! produce xs
        ]

第一次迭代:l = [A,B,C,D] - 不为空,在第二次匹配的情况下,我们将得到x = A,xs = [B,C,D]。 'for'部分列表表达式将产生[AB,AC,AD]以及将produce应用于xs的结果。

第二次迭代:l = [B,C,D]不为空所以第二次匹配的情况我们将x = B,xs = [C,D]。 'for'部分列表表达式将产生[BC,BD]和将produce应用于xs的结果。

第3次迭代:l = [C,D]在第二次匹配情况下不为空,我们将x = C,xs = [D]。 'for'部分列表表达式将产生[CD]和将produce应用于xs的结果。

第4次迭代:l = [D]包含一个元素 - &gt;返回空列表。

最终结果将是[AB,AC,AD] ++ [BC,BD] ++ [CD]

的串联

答案 5 :(得分:1)

这是在F#中实现List monad的一个恰当的激励示例。使用F#计算表达式,我们得到:

type ListMonadBuilder() = 
    member b.Bind(xs, f) = List.collect f xs
    member b.Delay(f)    = fun () -> f()
    member b.Let(x, f)   = f x
    member b.Return(x)   = [x]
    member b.Zero()      = []

let listM = new ListMonadBuilder()

现在,为了解决原始问题,我们只需使用List monad。

let run = listM {
    let! x = ['A' .. 'D']
    let! y = List.tail [ x  .. 'D']
    return string x + string y
}
<#> run();;在F#Interactive中将返回所需的结果。

关于使用List monad的另一个例子,我们可以获得Pythagorean三元组<= n

let pythagoreanTriples n = listM {
    let! c = [1 .. n]
    let! b = [1 .. c]
    let! a = [1 .. b]
    if a*a + b*b = c*c then return (a, b, c)
}

在F#interactive中运行pythagoreanTriples 10 ();;返回:

val it : (int * int * int) list = [(3, 4, 5); (6, 8, 10)]