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

时间:2018-03-20 22:41:27

标签: f# iteration sublist

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

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]]

2 个答案:

答案 0 :(得分:3)

最近已将

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]]

答案 1 :(得分:2)

您可以使用最近添加的List.transpose功能。但是,自己创造这样的功能总是好的。如果您想自己解决问题,请考虑一般算法来解决您的问题。一个是。

  1. 从每个列表的第一个元素中创建一个新列表
  2. 删除每个列表的第一个元素
  3. 如果您以空列表结束,则以步骤1)重复
  4. 这可能是解决问题的第一次尝试。此时,功能名称已组成。

    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))
    

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

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

    接下来,我们需要实现其余功能allEmptypickFirstsdropFirsts

    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]]
    

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