F# - 如何制作列表中的元素副本?

时间:2017-03-06 02:33:00

标签: list f#

我希望写一些可以复制列表中所有元素的东西。所以如果我想要2个列表

[1; 2; 3; 4]

它会变成

[1; 1; 2; 2; 3; 3; 4; 4]

所以我打算用

递归写一个函数
let rec dupeElem row count =
  match row with
  | [] -> []
  | hd::tl -> (makeCopy hd count) @ dupeElem tl count

其中count是我想要的副本数。该函数将获取列表中的每个头元素并将其发送到复制功能,以使副本插入到列表中。然后makeCopy看起来像:

let makeCopy elem Count =
  match Count with 
  | 0 -> []
  | 1 -> elem
  | 2 -> elem :: elem
  |....

但是当它返回dupeElem时我会收到错误。我知道做难事并不是最明智的想法,而是测试它是否可行。我如何修复/改进我的工作?

4 个答案:

答案 0 :(得分:7)

仅仅是为了非递归解决方案:

let xs = [1; 2; 3; 4; 5]
xs |> List.collect (fun x -> List.replicate 3 x)
//val it : int list = [1; 1; 1; 2; 2; 2; 3; 3; 3; 4; 4; 4; 5; 5; 5]

答案 1 :(得分:3)

makeCopy返回0案例的列表,但对于1案例,您返回的是单个元素。将1的大小写更改为以下内容应该可以修复编译时错误:

| 1 -> [elem]

对于案例2,您对::的使用无效,因为右侧不是列表,但它是单个元素。请考虑将其替换为以下任一项:

| 2 -> elem :: [elem]

或者...

| 2 -> [ elem; elem ]

答案 2 :(得分:2)

相互递归的方式:

let rec dupl n = function
    | []   -> []
    | h::t -> cons h (dupl n t) n
and cons h t = function
    | 0 -> t
    | n -> cons h (h::t) (n-1)

答案 3 :(得分:0)

s952163的回答简洁明了。为了更加通用,如果您不想复制,可以定义函数f,g和h,并执行以下操作:

let xs = [1; 2; 3; 4]
let f = id // No need for type annotation, given the definitions of g and h
let g x = x * x
let h x = x * x * x
(List.zip3 xs xs xs) |> List.map (fun (a, b, c) -> [f a; g b; h c]) |> List.concat

对于您只想复制的特定情况,您可以执行

let f = id<int> // The type annotation is necessary

并且类似地对于g和h或者仅对所有三种情况使用f。当然,在这种情况下,s952163提出的解决方案更受欢迎。