在列表列表中排序索引-F#

在列表列表中排序索引-F#,f#,iteration,sublist,F#,Iteration,Sublist,目前,我有一个函数可以将列表中每个列表的第一个元素(浮动)返回到一个单独的列表中 let firstElements list = match list with | head::_ -> head | [] -> 0.00 我的问题是,当我不知道这个列表有多长时,如何扩展它以将相同索引中的元素返回到不同的列表中?比如说 let biglist = [[1;2;3];[4;5;6];[7;8;9]] 如果我不知道这个列表的长度,那么最有效、最安全的方法是什

目前,我有一个函数可以将列表中每个列表的第一个元素(浮动)返回到一个单独的列表中

let firstElements list =
    match list with
    | head::_ -> head
    | [] -> 0.00
我的问题是,当我不知道这个列表有多长时,如何扩展它以将相同索引中的元素返回到不同的列表中?比如说

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)
  • 这可能是解决这个问题的第一次尝试。此时,函数名已组成

    let transpose lst =
        if allEmpty lst 
        then // Some Default value, we don't know yet
        else ...
    
    else
    分支如下所示。首先,我们要选择每个元素的第一个元素。我们设想一个函数
    pickFirsts
    来完成这个任务。所以我们可以编写
    pickFirsts lst
    。结果是一个列表,它本身是新列表的第一个元素

    新列表是剩余列表的结果。首先,我们再次设想一个函数,它删除每个子列表的第一个元素
    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))
    
    此时,我们可以考虑默认值<代码>转置需要返回一个值,以防它以空列表的空列表结束。因为我们使用
    转置的结果
    向其添加元素。它的结果必须是一个
    列表
    。最好的默认值是一个空列表。因此,我们最终得到了

    let rec transpose lst =
        if   allEmpty lst
        then []
        else (pickFirsts lst) :: (transpose (dropFirsts lst))
    
    接下来,我们需要实现剩余的函数
    allEmpty
    pickFirsts
    dropFirsts

    pickFirst
    很容易。我们需要迭代每个元素,并且必须返回第一个值。我们通过
    list.head
    获得列表的第一个值,并对其进行迭代,将每个元素转换为一个新的列表,这就是
    list.map
    所做的

    let pickFirsts lst = List.map List.head lst
    
    dropFirsts
    需要迭代每个元素,只需删除第一个元素,或者换句话说,保留列表的剩余/尾部

    let dropFirsts lst = List.map List.tail lst
    
    剩下的
    allEmpty
    是一个谓词,如果列表列表是否为空,则返回true/false。返回值为
    bool
    ,我们需要另一个允许返回另一种类型的函数,即列表。这通常是使用
    List.fold
    的原因。实现可以如下所示:

    let allEmpty lst   = 
        let folder acc x =
            match x with
            | [] -> acc
            | _  -> false
        List.fold folder true lst
    
    它以
    true
    作为默认值开始。只要找到空列表,它就会返回默认值不变。一旦在任何列表中找到一个元素,它将返回
    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]]
    

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

    看起来像是一个分组方式。这看起来像是您实际要做的是转置矩阵;也许可以研究一下这方面的算法。(如果我理解正确,FSharp.Core将来将包含一个函数。)@TeaDrivenDev的可能副本它已经在那里了这是比我更好的答案。向我投最大的一票。我应该感到骄傲