【问题标题】:F# Adding to Lists not Taking PlaceF# 添加到未发生的列表
【发布时间】:2014-10-05 01:56:24
【问题描述】:

大家好,我的 F# 程序遇到了一些问题。我基本上有一个未知数量的大小为 12 的浮点列表(通过读取文件和解析来处理),我想获取这些列表并将它们拆分为每个元素对应的 12 个列表。因此,例如,我希望列表中的所有第 5 个元素都进入 n5 等等。我的代码顶部有我的列表声明

let (n1: float list) = []
let (n2: float list) = []
let (n3: float list) = []
let (n4: float list) = []
let (n5: float list) = []
let (n6: float list) = []
let (n7: float list) = []
let (n8: float list) = []
let (n9: float list) = []
let (n10: float list) = []
let (n11: float list) = []
let (n12: float list) = []

递归访问器

let rec accsessline line = 
  if line = [] then
    ()  
   else      
     let (year, values) = ParseLine line.Head   
     (Pusher values)
     accsessline line.Tail

以及在上述代码段中调用的列表填充方法(注意我的评论)

let Pusher (yearsFalls : float list)  =
    printfn "years falls are %f" yearsFalls.[6] //this line correctly accesses and prints the right element (6th) in each list yearsFalls.
    yearsFalls.[0] :: n1
    yearsFalls.[1] :: n2
    yearsFalls.[2] :: n3
    yearsFalls.[3] :: n4
    yearsFalls.[4] :: n5
    yearsFalls.[5] :: n6
    yearsFalls.[6] :: n7
    yearsFalls.[7] :: n8
    yearsFalls.[8] :: n9
    yearsFalls.[9] :: n10
    yearsFalls.[10] :: n11
    yearsFalls.[11] :: n12

现在一切正常,它只是我试图添加到这些不起作用的列表的部分。当我在调用上述 accessline 函数后打印出 n1-n12 列表之一时,正确的元素是 access,如我的 printfn 输出所示,它打印出每行的第 6 个元素(我的代码中唯一的注释),但是列表打印为空括号“[]”。只是实际添加到 n1-n12 列表中并没有发生。你知道我到底需要做什么才能让实施工作吗?感谢您的宝贵时间!

【问题讨论】:

  • 很难弄清楚你要做什么。但是您的monthPusher () 函数返回列表(yearsFalls.[11] :: n12)。在表达式 (yearsFalls.[...] :: n...) 中构造的前 11 个列表被有效地忽略,并且对 monthPusher() 函数之外的数据没有影响
  • 您建议如何进行这些更改?我尝试对我的 Pusher n1=yearsFalls.[0] 的所有行进行以下编辑:: n1 并这样做让 n1 = yearsFalls.[0] :: n1。而且它并没有真正奏效
  • 很难说你想在这里做什么,但我认为你的数据结构的选择是非常不幸 - 看起来你想要一对(year,value) 好的,然后您使用这些 values 的方式表明这些又是不少于 12 个列表? - 但是什么是 year-falls? - 剩下的你的代码可以工作 - 当你声明 12 个空列表时,你会得到 12 个空列表 - 我建议设置断点,调试并使用类型的工具提示

标签: f#


【解决方案1】:

您应该意识到F# list 是一个不可变的数据结构,正如下面使用 FSI 进行的简单实验所示:

> let ll: int list = [];;
val ll : int list = []
> 1::ll;;
val it : int list = [1] // expression value is a new list
> ll;;
val it : int list = []  // ...but original list did not change ?!

为了在列表中累积元素,F# 中至少存在两种​​方式:

  • 强制列表可变的非惯用方法之一:

> let mutable ll: int list = [];;
val mutable ll : int list = []
> ll <- 1 :: ll;; // mutate list by prepending an element
val it : unit = ()
> ll;;
val it : int list = [1] // list has changed
  • 组合功能应用程序的惯用方法之一:

> let prepend l ll = l :: ll;;
val prepend : l:'a -> ll:'a list -> 'a list
> [] |> prepend 1;;
val it : int list = [1]
> [] |> prepend 1 |> prepend 2;;
val it : int list = [2; 1]
........................

这也许提供了足够的线索来以非惯用方式实现您的程序。对于考虑以下更简单但类似问题的解决方案的惯用解决方案可能会有所帮助:假设您需要对整数列表进行分区,将奇数元素放入一个列表中,将偶数元素放入另一个列表中。下面的 sn-p 会做:

>let rec partition (odds,evens) ll =
    match ll with
    | [] -> (odds,evens)
    | h::t -> match h % 2 with
              | 0 -> partition (odds, h :: evens) t
              | _ -> partition (h :: odds, evens) t;;

val partition :
  odds:int list * evens:int list -> ll:int list -> int list * int list

> partition ([],[]) [1;42;-3;7;14];;
val it : int list * int list = ([7; -3; 1], [14; 42])

只需了解上述工作原理,并对您的原始问题应用类似的方法即可。祝你好运!

【讨论】:

    【解决方案2】:

    正如 Gene 所指出的,您正在使用不可变数据结构,因此您的 n1..n12 列表在引用时将始终为空。相反,您需要累积列表,然后返回您可以存储的列表列表。或者,在声明每个 n1..n12 列表时,您可以在声明时找到每个列表的元素。

    我提出的解决方案是按照您建议的方式分配假定未知数量的长度为 12 的整数列表的元素:

    // Some list to work on as input, read from your file for instance
    let list = 
        [
            [1..12] 
            [1..12]
            [1..12]
            [1..12]
            [1..12]
            [1..12]
            [1..12]
            [1..12]
            [1..12]
        ]
    let distributeElements inputList =
        // For each sublist of the inputList take out the appropriate element and add it to the list, then move on to the next sublist
        let rec gatherFromEachSubList (inputList: list<list<int>>) indexOfInput elementNumber accum =
            if indexOfInput < (inputList |> List.length) then 
                let newAccum = inputList.[indexOfInput].[elementNumber - 1] :: accum
                gatherFromEachSubList inputList (indexOfInput+1) elementNumber newAccum
            else 
                accum
    
        // For each category (n1..n12) gather from the sublists of the inputlist
        let rec gatherLists inputList elementNumber accum =
            if elementNumber > 0 then
                let newAccum = gatherFromEachSubList inputList 0 elementNumber List.empty :: accum
                gatherLists inputList (elementNumber - 1) newAccum
            else
                accum
        gatherLists inputList 12 List.empty
    
    [<EntryPoint>]
    let main argv =     
        let result = distributeElements list
        result |> List.map (fun a -> printfn "%A" a) |> ignore
        0 // return an integer exit code
    

    以及在 FSI 中运行时的结果:

    let result = distributeElements list
    result |> List.map (fun a -> printfn "%A" a) |> ignore;;
    
    [1; 1; 1; 1; 1; 1; 1; 1; 1]
    [2; 2; 2; 2; 2; 2; 2; 2; 2]
    [3; 3; 3; 3; 3; 3; 3; 3; 3]
    [4; 4; 4; 4; 4; 4; 4; 4; 4]
    [5; 5; 5; 5; 5; 5; 5; 5; 5]
    [6; 6; 6; 6; 6; 6; 6; 6; 6]
    [7; 7; 7; 7; 7; 7; 7; 7; 7]
    [8; 8; 8; 8; 8; 8; 8; 8; 8]
    [9; 9; 9; 9; 9; 9; 9; 9; 9]
    [10; 10; 10; 10; 10; 10; 10; 10; 10]
    [11; 11; 11; 11; 11; 11; 11; 11; 11]
    [12; 12; 12; 12; 12; 12; 12; 12; 12]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-07
      相关资源
      最近更新 更多