list - F#:递归函数:连接 2 个具有公共(public)元素的列表

标签 list recursion f#

这就是我到目前为止所拥有的。感觉很接近,但我不确定如何解决第 84 行中的问题(第二行到最后一行: elif List.append(isolate(a),isolate(b)) != [] then List.append(isolate(a),隔离(b)))。

    (* val isolate : l:'a list -> 'a list when 'a : equality *)
    let rec isolate (l:'a list) = 
        match l with
        | [] -> []
        | x::xs ->
            if memberof(x,xs)
            then
                let xs = remove (x,l)
                isolate xs
            else isolate xs
    ( * val common : 'a list * 'a list -> 'a list when 'a : equality *)
    let rec common (k: 'a list, l:'a list) = 
        match ((k:'a list),(l:'a list)) with
        | (a, b) -> 
            if a=[] then []
            elif b=[] then []
            elif List.append(isolate(a),isolate(b)) != [] then List.append(isolate(a),isolate(b))
            else []

编辑:

要求发布完整代码:

(* val sumlist : l:float list -> float *)
let rec sumlist l =  
    match (l:float list) with
    | [] -> 0.0
    | a::x -> (sumlist x) + a
    (* :: creates a list. *)
sumlist([1.0;2.0;3.0])
(* val squarelist : l:float list -> float list *)
let rec squarelist l = 
    match (l:float list) with
    | [] -> []
    | a::x -> (a*a)::(squarelist x)

(* val mean : l:float list -> float *)
let mean l = 
    match (l:float list) with
    | [] -> 0.0
    | l -> (sumlist l)/(float)l.Length
mean([1.0;2.0;3.0])
(* val mean_diffs : l:float list -> float list *)
let mean_diffs l = 
    match l with
    set a = mean(l)

    | [] -> []
    let rec diffs (a,l)=
        match l with
        | x::xs -> (x-(mean(l))::diffs(xs)
        | [] -> l
mean_diffs([1.0;2.0;3.0])

(* val variance : l:float list -> float *)
let variance l = 
    match (l:float list) with
    | [] -> 0.0
    | l -> (sumlist (squarelist (mean_diffs l)))/(float)l.Length


(* End of question 1 *) (* Do not edit this line. *)

(* Question 2 *) (* Do not edit this line. *)

(* val memberof : 'a * 'a list -> bool when 'a : equality *)
let rec memberof l=
    match (l: 'a * 'a list) with
    | (t,[]) -> false
    | (t, x::xs) when t=x -> true
    | (t, x::xs) -> t=x || memberof(t,xs)

(* val remove : 'a * 'a list -> 'a list when 'a : equality *)
let rec remove ((k:'a),(l:'a list)) = 
    match l with
    | [] -> []
    | x::xs when x=k -> xs
    | x::xs ->x::(remove(k,xs))

(* End of question 2 *) (* Do not edit this line *)

(* Question 3 *) (* Do not edit this line *)

(* val isolate : l:'a list -> 'a list when 'a : equality *)
let rec isolate (l:'a list) = 
    match l with
    | [] -> []
    | x::xs ->
        if memberof(x,xs)
        then
            let xs = remove (x,l)
            isolate xs
        else isolate xs

(* End of question 3 *) (* Do not edit this line *)

(* Question 4 *) (* Do not edit this line *)

(* val common : 'a list * 'a list -> 'a list when 'a : equality *)
let rec common (k: 'a list, l:'a list) = 
    match ((k:'a list),(l:'a list)) with
    | (a, b) -> 
        if a=[] then []
        elif b=[] then []    
        elif List.append(isolate(a),isolate(b)) <> [] then List.append(isolate(a),isolate(b))
        else []
common([1.0;2.0;6.0;10.0],[5.0;6.0;10.0])

看来<>已经解决了这个问题,但是你对我的函数mean_diffs有什么建议吗?

最佳答案

由于这看起来您正在学习一门类(class),并且它是建立在之前的练习基础上的,因此代码将转换为更符合 F# 习惯的递归函数和标准化格式,以便在您访问 currying 时更容易使用它们。请参阅:F# for fun and profitFunctions as First-Class Values (F#)以及其他更先进的概念。

格式基本上是

let funXYZ list =
    let rec funXYZInner list acc =
        match list with
        | head :: tail ->
            let acc = (somefunc head) :: acc
            funXYZInner tail acc
        | [] -> acc
    funXYZInner list []

其中 funXYZ 是一个没有 rec 的公开函数名称。我不记得来源了,但是如果你可以实现一个需要rec并且rec不被暴露的函数,那么它会使代码更加可移植。

基本概念是获取一个列表并将该列表分为headtail:

head :: tail

然后你处理头部:

somefunc head

然后将结果累加到累加器

let acc = value :: acc
let acc = value + acc
let acc = acc + (value * value)

然后处理列表的其余部分,例如tail,传递累加器

funXYZInner tail acc

当输入列表匹配空时

| []

只返回累加器中累加的结果

acc

内部函数 funXYZInner 确实有一个 rec并使用 accumulator ,即acc。这将有助于理解如何使用 tail calls这将防止您在大型计算中耗尽内存。

您可能已经知道,使用 match 语句您希望覆盖 match 变量的所有情况。这是因为algebraic data types这就是您看到有关并非所有案例都被涵盖的警告的原因。如果您看到这些警告之一并且不知道为什么会收到它,则需要修复它们,否则就会面临意外运行时错误或崩溃的风险。

虽然您提供的代码只能用于浮点类型列表,但将来要使其适用于更多类型,您将需要了解 LanguagePrimitives.GenericZero<^T> Type Function (F#) .

由于需要而添加了一些更基本的功能,例如反向,并帮助显示随着示例变得更加复杂的进展。

事实上,示例是建立在自身之上的,并且您在上一个示例中出现了特定错误,因此最好为示例提供更好的基础,这应该可以减轻首次学习递归函数时遇到的常见问题。

关于累加器,累加器可以保存不同的类型,例如floatlistint,并且递归函数中可以使用多个累加器,例如分子Acc分母Acc。另外,通过提取累加器值的计算,例如 let acc = ...,当您使用更高级的函数时,您可以传入一个函数来替换该计算。

有一个predicate不使用累加器的函数memberof。谓词是一个返回 true 或 false 的函数,一旦达到所需的值,您就可以停止处理列表的其余部分。

还值得注意的是,虽然某些函数可以调用早期定义的函数,但示例不会进行调用,以便它们可以一次性处理列表。当函数使用列表调用其他函数时,每个函数都必须处理整个列表才能返回结果。通过使用rec函数,有时可以通过对头部进行多次计算来处理一次列表。然而,有时这是无法做到的。我没有以某种方式最大化功能,而是给它们留下了一种为学习提供更多变化的方式。请随意重写它们,这将导致 function composition .

您可能会对这些示例有更多疑问,因此请作为单独的问题提出,而不是在此问题的基础上提出。

所有代码

// val reverse : l:'a list -> 'a list
let reverse l =
    let rec reverseInner l acc =
        match l with
        | x::xs -> 
            let acc = x :: acc
            reverseInner xs acc
        | [] -> acc
    reverseInner l []

reverse [ 3.0; 2.0; 1.0 ]  // val it : float list = [1.0; 2.0; 3.0]    

// val length : l:'a list -> int
let length l =
    let rec lengthInner l acc =
        match l with
        | x::xs -> 
            let acc = acc + 1
            lengthInner xs acc
        | [] -> acc
    lengthInner l 0

length [ 3.0; 2.0; 1.0 ]  // val it : int = 3

// val sum : l:float list -> float
let sum l =
    let rec sumInner l acc =
        match l with
        | x::xs -> 
            let acc = acc + x
            sumInner xs acc
        | [] -> acc
    sumInner l 0.0

sum [ 1.0; 2.0; 3.0 ]  // val it : float = 6.0

// val square : l:float list -> float list
let square (l : float list) = 
    let rec squareInner l acc =
        match l with
        | x::xs -> 
            let acc = (x * x) :: acc
            squareInner xs acc
        | [] -> reverse acc
    squareInner l []

square [ 1.0; 2.0; 3.0 ]  // val it : float list = [1.0; 4.0; 9.0]

// val mean : l:float list -> float
let mean l = 
    let rec meanInner l sumacc lengthacc =
        match l with
        | x::xs -> 
            let sumacc = sumacc + x
            let lengthacc = lengthacc + 1.0
            meanInner xs sumacc lengthacc
        | [] -> sumacc / lengthacc
    meanInner l 0.0 0.0

mean([1.0;2.0;3.0]) // val it : float = 2.0

// val mean_diffs : l:float list -> float list
let meanDiff l = 
    let rec meanDiffInner l m acc =
        match l with
        | x::xs -> 
            let diff = (x - m)
            let acc = diff :: acc
            meanDiffInner xs m acc
        | [] -> reverse acc
    meanDiffInner l (mean l) []

meanDiff [ 1.0; 2.0; 3.0 ]  // val it : float list = [-1.0; 0.0; 1.0]


// From: https://en.wikipedia.org/wiki/Variance
// Suppose a population of numbers consists of 3, 4, 7, and 10. 
// The arithmetic mean of these numbers, often informally called the "average", is (3+4+7+10)÷4 = 6. 
// The variance of these four numbers is the average squared deviation from this average. 
// These deviations are (3–6) = –3, (4–6) = –2, (7–6) = 1, and (10–6) = 4. 
// Thus the variance of the four numbers is ((-3)^2 + (-2)^2 + (1)^2 + (4)^2) / 4 = 15/2 = 7.5

// val variance : l:float list -> float
let variance l = 
    let deviations = meanDiff l
    let rec varianceInner l numeratorAcc denomenatorAcc =
        match l with
        | devation::xs ->
            let numeratorAcc = numeratorAcc + (devation * devation) 
            let denomenatorAcc = denomenatorAcc + 1.0
            varianceInner xs numeratorAcc denomenatorAcc
        | [] -> numeratorAcc / denomenatorAcc
    varianceInner deviations 0.0 0.0

variance [ 1.0; 2.0; 3.0 ]          // val it : float = 0.6666666667
variance [ 3.0; 4.0; 7.0; 10.0 ]    // val it : float = 7.5


(* End of question 1 *) (* Do not edit this line. *)

(* Question 2 *) (* Do not edit this line. *)

// val memberof : l:'a list -> item:'a -> bool when 'a : equality
let memberof l item =
    let rec memberInner l item =
        match l with
        | x::xs -> 
            if x = item then
                true
            else 
                memberInner xs item
        | [] -> false
    memberInner l item

memberof [ 1.0; 2.0; 3.0 ] 0.0  // val it : bool = false
memberof [ 1.0; 2.0; 3.0 ] 1.0  // val it : bool = true
memberof [ 1.0; 2.0; 3.0 ] 2.0  // trueval it : bool = true
memberof [ 1.0; 2.0; 3.0 ] 3.0  // val it : bool = true
memberof [ 1.0; 2.0; 3.0 ] 4.0  // val it : bool = false

// val remove : l:'a list -> item:'a -> 'a list when 'a : equality
let remove l item =
    let rec removeInner l item acc =
        match l with
        | x::xs ->
            if x = item then
                removeInner xs item acc
            else
                let acc = x :: acc
                removeInner xs item acc
        | [] -> reverse acc
    removeInner l item []

remove [ 1.0; 2.0; 3.0 ] 0.0    // val it : float list = [1.0; 2.0; 3.0]
remove [ 1.0; 2.0; 3.0 ] 1.0    // val it : float list = [2.0; 3.0]
remove [ 1.0; 2.0; 3.0 ] 2.0    // val it : float list = [1.0; 3.0]
remove [ 1.0; 2.0; 3.0 ] 3.0    // val it : float list = [1.0; 2.0]
remove [ 1.0; 2.0; 3.0 ] 4.0    // val it : float list = [1.0; 2.0; 3.0]

(* End of question 2 *) (* Do not edit this line *)

(* Question 3 *) (* Do not edit this line *)

// val isolate : list:'a list -> 'a list when 'a : equality
let isolate list =
    let rec isolateInner searchList commonlist =
        match searchList with
        | x::xs ->
            if (memberof commonlist x) then
                isolateInner xs commonlist
            else
                let commonlist = (x :: commonlist)
                isolateInner xs commonlist
        | [] -> reverse commonlist
    isolateInner list []

isolate [ 1.0; 2.0; 3.0 ]                                    // val it : float list = [1.0; 2.0; 3.0]
isolate [ 1.0; 1.0; 2.0; 3.0 ]                               // val it : float list = [1.0; 2.0; 3.0]
isolate [ 1.0; 2.0; 2.0; 3.0 ]                               // val it : float list = [1.0; 2.0; 3.0]
isolate [ 1.0; 2.0; 3.0; 3.0 ]                               // val it : float list = [1.0; 2.0; 3.0]
isolate [ 3.0; 2.0; 1.0; 1.0; 2.0; 3.0; 2.0; 1.0; 1.0; 3.0]  // val it : float list = [3.0; 2.0; 1.0]

(* End of question 3 *) (* Do not edit this line *)

(* Question 4 *) (* Do not edit this line *)

// val common : a:'a list -> b:'a list -> 'a list when 'a : equality
let common a b = 
    let rec commonInner a b acc =
        match (a,b) with
        | (x::xs,b) ->
            if (memberof acc x) then
                commonInner xs b acc
            else
                let acc = x :: acc
                commonInner xs b acc
        | ([],y::ys) ->
            if (memberof acc y) then
                commonInner [] ys acc
            else
                let acc = y :: acc
                commonInner [] ys acc
        | ([],[]) -> reverse acc
    commonInner a b []

common [ 1.0; 2.0; 6.0; 10.0] [ 5.0; 6.0; 10.0 ]   // val it : float list = [1.0; 2.0; 6.0; 10.0; 5.0]

关于list - F#:递归函数:连接 2 个具有公共(public)元素的列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35098970/

相关文章:

javascript - 将 ngFor 列表中的按钮更改为文本字段以获取值,然后提交进行处理

Java递归方法一次打印字符串中的一个单词而不循环

f# - 完整模式匹配的编译时约束

recursion - 具有递归的 F# 求和类型?

javascript - 如何在以前使用 div 的脚本中合并要调用的列表项?

python - 如何在Python中将数据框的每一行合并到一个列表中

boolean 值比较的 Python 列表给出了奇怪的结果

javascript - 递归生成器 JavaScript

algorithm - 2d树最近邻算法说明

arrays - 快速将文本数据读入数组