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

时间:2022-07-17 22:05:17

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元素列表。

5 个解决方案

#1


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.

#2


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

#3


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

Note: this function is O(n^2). Consider using Seq.map and Seq.filter instead:

注意:此函数为O(n ^ 2)。请考虑使用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)。

#4


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

#5


Other proposition of mine using Fold. It is linear function O(N). But definitely not so elegant and simple as DannyAsher's solution:

我使用Fold的其他命题。它是线性函数O(N)。但绝对不像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

#1


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.

#2


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

#3


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

Note: this function is O(n^2). Consider using Seq.map and Seq.filter instead:

注意:此函数为O(n ^ 2)。请考虑使用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)。

#4


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

#5


Other proposition of mine using Fold. It is linear function O(N). But definitely not so elegant and simple as DannyAsher's solution:

我使用Fold的其他命题。它是线性函数O(N)。但绝对不像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