在列表列表中对索引进行排序 - F#

Sorting indexes in list of lists - F#

目前我有一个函数return每个列表的第一个元素(浮点数),从一个列表到一个单独的列表。

let firstElements list =
    match list with
    | head::_ -> head
    | [] -> 0.00

我的问题是,当我不知道这个列表有多长时,如何将它扩展到不同列表中同一索引处的 return 个元素?例如

let biglist = [[1;2;3];[4;5;6];[7;8;9]]

如果我不知道这个列表的长度,最有效和最安全的方法是什么

[[1;4;7];[2;5;8];[3;6;9]]

List.transpose 最近已添加到 FSharp.Core

let biglist = [[1;2;3];[4;5;6];[7;8;9]]

let res = biglist |> List.transpose

//val res : int list list = [[1; 4; 7]; [2; 5; 8]; [3; 6; 9]]

您可以使用最近添加的List.transpose功能。但是自己足够好来创建这样的功能总是好的。如果你想自己解决问题,想一个通用的算法来解决你的问题。一个是。

  1. 从每个列表的第一个元素创建一个新列表
  2. 您删除每个列表的第一个元素
  3. 如果以空列表结束则结束,否则重复步骤 1)

这可能是解决问题的第一次尝试。函数名到此为止。

let transpose lst =
    if allEmpty lst 
    then // Some Default value, we don't know yet
    else ...

else 分支如下所示。首先,我们要选择每个元素的第一个元素。我们想象一个函数 pickFirsts 来完成这个任务。所以我们可以写 pickFirsts lst。结果是一个列表,它本身是新列表的第一个元素。

新列表是剩余列表的结果。首先,我们再次想象一个函数,它删除每个 sub-list dropFirsts lst 的第一个元素。在该列表上,我们需要重复步骤 1)。我们通过递归调用 transpose 来做到这一点。 总的来说,我们得到:

let rec transpose lst =
     if   allEmpty lst
     then // Some Default value, we don't know yet
     else (pickFirsts lst) :: (transpose (dropFirsts lst))

此时我们可以想到默认值。 transpose 需要 return 一个值,以防它以空列表的空列表结尾。当我们使用 transpose 的结果向其添加一个元素时。它的结果必须是 list。最好的默认值是一个空列表。所以我们最终得到了。

let rec transpose lst =
    if   allEmpty lst
    then []
    else (pickFirsts lst) :: (transpose (dropFirsts lst))

接下来我们需要实现剩余的函数allEmptypickFirstsdropFirsts

pickFirst 很简单。我们需要遍历每个元素,并且必须 return 第一个值。我们通过 List.head 获得列表的第一个值,然后迭代它并将每个元素变成一个新列表就是 List.map 所做的。

let pickFirsts lst = List.map List.head lst

dropFirsts需要遍历每个元素,只删除第一个元素,或者换句话说保留列表的remaining/tail。

let dropFirsts lst = List.map List.tail lst

剩下的 allEmpty 是一个谓词 return true/false 如果我们有一个空的列表列表。对于 return 值为 bool 的情况,我们需要另一个允许 return 另一种类型是列表的函数。这通常是使用 List.fold 的原因。实现可能如下所示:

let allEmpty lst   = 
    let folder acc x =
        match x with
        | [] -> acc
        | _  -> false
    List.fold folder true lst

默认以true开头。只要它找到空列表,它 return 的默认值就不会改变。一旦找到一个元素,在任何列表中,它将 return false(非空)作为新的默认值。

全部代码:

let allEmpty lst   = 
    let folder acc x =
        match x with
        | [] -> acc
        | _  -> false
    List.fold folder true lst

let pickFirsts lst = List.map List.head lst
let dropFirsts lst = List.map List.tail lst


let rec transpose lst =
    if   allEmpty lst
    then []
    else (pickFirsts lst) :: (transpose (dropFirsts lst))


transpose [[1;2;3];[4;5;6];[7;8;9]]

另一种方法是将其转换为二维可变数组。也做长度检查。进行转换并再次 return 可变数组作为不可变列表。