在列表F#中排序列表

时间:2010-07-03 22:33:06

标签: list f# sorting

我正在尝试对位置列表中的每个位置(列表)进行排序。目前我这样做:

type Position = Position of  list<int * Piece>

和我的职能:

let SortPositionList positionList : Position list = 
let rec loop list =
    match (list: Position list) with
    | [] -> []
    | hd::tl -> [List.sortBy(fun (x:(int*Piece)) -> fst x)(GetInternStruct(hd))::loop tl]
loop positionList

在我看来,这可以通过递归排序列表的实际头部然后将其与列表的其余部分连接来完成,但它不起作用。此函数中的错误是:

类型不匹配。期望一个(int * Piece)列表列表但给出一个(int * Piece)列表列表类型'int * Piece'与类型'(int * Piece)列表'不匹配,带下划线的loop tl < / p>

类型不匹配。期望一个位置列表,但给出一个(int * Piece)列表列表列表类型'Position'与类型'(int * Piece)列表'不匹配,在下划线调用loop,loop positionList

希望你能提前帮助

Pedro Dusso

修改 AList.map传递排序函数会是一个很好的方法吗?

let SortPositionList (positionList : Position list) =
    List.map (fun (Position(position)) -> List.sort(position)) positionList

由于我的Position结构是一个(int * Piece)lst,我在无穷大的函数中对它进行模式匹配并对其进行排序。

感谢您的回答!

4 个答案:

答案 0 :(得分:4)

如何:

let SortPositionList (positionList : Position list) =
    List.map (fun pos -> List.sortBy (fun (index, _) -> index) pos) positionList

您正在使用的是位置列表上的List.map,将每个元素(本身为列表)映射到List.sortBy函数。这需要一个返回键进行比较的函数。在这种情况下,我们使用内置模式匹配来匹配'int * Piece'元组中的索引。

答案 1 :(得分:3)

一般来说,F#中有两种处理方式。您可以显式使用递归,也可以使用现有函数。在您的情况下,您需要以嵌套方式执行两项操作 - 您需要遍历外部列表并对内部列表进行排序。排序可以使用List.sortBy完成,迭代(投影)可以使用List.map完成。

要纠正你的原始方法(使用递归) - 我稍微简化了一下(因为你不需要loop函数 - 你可以使函数本身递归):

let rec sortPositionList list =  
  match list with 
  | [] -> [] 
  | hd::tl -> 
    // Sort the list of positions first - by storing this as a new value
    // using 'let', you get more readable code (and you can use IntelliSense
    // to explore the type of 'sorted' and understand what's going on)
    let sorted = List.sortBy (fun (x, _) -> x) (GetInternStruct(hd))

    // As Brian suggests, more idiomatic F# encoding of the line would be:
    //   let sorted = GetInternStruct(hd) |> List.sortBy (fun (x, _) -> x)
    // but both of the options would work in this case.

    // Note: The result shouldn't be wrapped in '[ .. ]'. The operator '::'
    // takes an element and a list and returns a new list created by 
    // prepending the element in front of the list
    sorted::(sortPositionList tl)

使用现有功能(List.map)的解决方案已由JDU发布。我只想补充一点,他使用部分函数应用程序 - 所以传递给List.map的参数是一个函数。如果这让人感到困惑,你可以明确地使用lambda函数重写它:

let SortPositionList (positionList) = 
  List.map (fun positions -> 
    List.sortBy (fun (index, _) -> index) positions) positionList 

使用流水线操作符和fst函数而不是显式lambda参数(如Brian所提到的),可以更加惯用地编写:

let SortPositionList (positionList) = 
  positionList |> List.map (fun positions -> 
    positions |> List.sortBy fst)  

这意味着与JDU发布的代码完全相同,但您可能会发现它更具可读性。最后,你可以使用序列表达式编写相同的东西(在我看来,这可能是最优雅的选项):

let SortPositionList (positionList) = 
  [ for positions in positionList do
      yield positions |> List.sortBy fst ]

编辑我在这里编写的函数使用的是(int*Point) list list类型的值,而不是Positions list类型的值。要更改此设置,您需要添加一些包装和展开。递归实现应该是:

  match list with         // List is always 'Positions', so we use pattern 
  | Positions [] -> []    // matching to unwrap the underlying list in 
  | Positions (hd::tl) -> // both cases
    // Wrap the resulting list into the positions type
    let sorted = Positions(List.sortBy (fun (x, _) -> x) (GetInternStruct(hd)))
    (sorted::(sortPositionList tl))

同样,对于List.map实施:

let SortPositionList (positionList) = 
  positionList |> List.map (fun (Positions positions) -> // pattern matching
    positions |> List.sortBy fst |> Positions)  // wrapping

答案 2 :(得分:2)

你做错了。 :)

我不知道你要做什么,但看着你的代码,我只知道这是错的,所以这就是我所看到的。

首先,你有

... List.sortBy blah1 blah2 ...

这是非惯用的,你想要

... blah2 |> List.sortBy blah1 ...

这将有助于类型推断。这种情况分为第二个问题,即

(fun (x:(int*Piece)) -> fst x)

是胡说八道。你可以写

(fun (i:int,p:Piece) -> i)

(fun (i,p) -> i)

或只是

fst

这意味着同样的事情,但你写的东西对人类来说是难以理解的(无论如何)。我希望也许你最初可能因为没有管道启动而陷入困境。

最后,更多的是,代码示例中缺少空格也使其无法读取;

)(

中间没有空格,并使用更多的水平和垂直空格来使代码的解析更加明显。

这主要是风格和肤浅的反馈,但我认为如果你解决这个问题,那些没有解决的类型的深层问题将开始变得更有意义并且变得更加明显。

答案 3 :(得分:1)

let apply f (Position xs) = Position(f xs)
let sorts = List.map (apply List.sort)