简体   繁体   English

所有选择F#中的列表 - 更优雅和简单

[英]All picks of a list in F# - more elegant and simple

Could someone propose better and/or more elegant implementation of this: 有人可以提出更好和/或更优雅的实现:

let each xs = 
    let rec each' acc left right = 
        match right with
        | [] -> acc
        | right ->  let new_left  = left @ [List.hd right]
                    let next   = List.tl right
                    let result = (List.hd right), left @ next
                    each' (result::acc) new_left next
    each' [] [] xs

It do that: 它做到了:

> each [1..3];;
val it : (int * int list) list = [(3, [1; 2]); (2, [1; 3]); (1, [2; 3])]

This function could return the result in reverse direction, too. 此函数也可以反向返回结果。 The idea is to get all elements as tuples with an element and list of rest elements. 我们的想法是将所有元素作为元组,包含元素和rest元素列表。

The semantic is slightly different here, but from the example you give Set might be a good fit: 这里的语义略有不同,但是从你给出的示例Set可能是一个很好的选择:

let each xs =
    let X = set xs                           
    [ for x in xs -> (x, X - set [x]) ]


> fsi.AddPrinter( fun (x:Set<int>) -> sprintf "%A" (Set.to_list x))
> each [1..3];;
> val it : (int * Set<int>) list = [(1, [2; 3]); (2, [1; 3]); (3, [1; 2])]

// Edited as per comments.

How about: 怎么样:

let rec each = function
| x :: xs -> (x,xs) :: (each xs |> List.map (fun (y,ys) -> (y,x::ys)))
| [] -> []

Or a tail recursive equivalent (producing the lists in reverse order): 或尾递归等价(以相反的顺序产生列表):

let each lst =
  let rec helper acc seen = function
  | [] -> acc
  | x :: xs -> 
      helper ((x,seen)::(acc |> List.map (fun (y,ys) -> (y,x::ys)))) (x::seen) xs
  helper [] [] lst
let each l = l |> List.map (fun x -> x, List.filter (fun y -> y <> x) l)

Note: this function is O(n^2). 注意:此函数为O(n ^ 2)。 Consider using Seq.map and Seq.filter instead: 请考虑使用Seq.map和Seq.filter:

let each l = l |> Seq.map (fun x -> x, Seq.filter (fun y -> y <> x) l)

Seq version has a performance of O(n). Seq版本的性能为O(n)。

This is not much better, if any, than the original solution, but here it goes. 如果有的话,这比原始解决方案要好得多,但在这里它会更好。 This version avoids the list appends by using a utility function to merge the reversed left list with the tail of the right. 此版本通过使用实用程序函数将反向左侧列表与右侧尾部合并来避免列表追加。 Also, it uses pattern matching instead of the head and tail functions. 此外,它使用模式匹配而不是头部和尾部功能。

let rec ljoin revleft right =  
  match revleft with 
       | [] -> right 
       | (x::xs) -> ljoin xs (x::right)                                                                                   
let each xs =
    let rec each' acc left right =
       match right with
       | [] -> acc
       | (y::ys) ->
           let result = y, ljoin left ys 
           each' (result::acc) (y::left) ys
    each' [] [] xs

Other proposition of mine using Fold. 我使用Fold的其他命题。 It is linear function O(N). 它是线性函数O(N)。 But definitely not so elegant and simple as DannyAsher's solution: 但绝对不像DannyAsher的解决方案那么优雅和简单:

let each5 xs =  let fu (left, next, acc) x = left@[x], List.tl next, (x, left@(List.tl next))::acc
                let (x, y, res) = List.fold fu ([], xs, []) xs
                res

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM