4.2.2 计算数据

来源:互联网 发布:英克软件 下载 编辑:程序博客网 时间:2024/06/06 02:20

4.2.2 计算数据

 

在这个应用程序的第一个版本中,我们将只打印标签,以及图表中每一项所占比例(百分比)。

要计算百分比,就需要知道列表中所有项目数值总和,这个值用清单 4.4 中的函数 calculateSum 来计算。

 

清单 4.4 计算列表中的数值和 (F# Interactive)

> let rec calculateSum(rows) =

   matchrows with | [] -> 0  <-- 空列表返回 0

   | (_, value)::tail ->    [1]

     let remainingSum = calculateSum(tail)  <-- 递归计算列表尾元素的和

     value + remainingSum

;;

val calculateSum : ('a * int) list ->int

 

> let sum = calculateSum(testData);;

val sum : int = 579

 

> 123.0 / float(sum) * 100.0;;  [2]

val it : float = 21.24352332

 

这个函数再次展示了处理列表的递归模式。如果我们还反复写同样的模式代码,可能会出错了(重复既无乐趣,也无聊);理想情况下,只应该写每个版本的独特部分的代码,我们自己不需要重复。对前面的示例,这个异议是有效的,我们可写得更简洁,在后面的章节将学习如何实现。在许多函数程序中,仍然需要递归与模式匹配,所以,看看另外的示例并熟悉概念是很有用的。

对于空列表,函数 calculateSum 只返回 0;对于 cons cell,以递归方式对列表尾(原始列表减去第一个元素)中的值求和,然后,把这个结果加到头(列表中的第一项)中的值上。这段代码中的模式配,演示了一个值得讨论的重要模式。在第二个分支中[1],我们需要分解 cons cell,因此,按照 head::tail 模式,匹配列表。但是,代码比这个要更复杂一些,因为在同时,还要根据分解元组,写作 (first, second) 的模式,匹配列表头。这是因为,列表包含了元组,第一个参数是标题,第二个参数是数值。在示例中,我们只要读数值,而忽略标题,因此,使用下划线模式忽略元组的第一个成员。如果我们把所有这些模式组合在一起,就得到 (_, value)::tail,这就是我们在代码中所使用的。

从 F# Interactive 所输出的函数签名,可以看到,函数取一个元组列表作为输入,返回整数;输入元组的类型是 'a * int,表示该函数是泛型,处理的列表可以包含任意元组,只要第二个元素是整数,第一个元素的类型不确定,因为其值在模式匹配中被忽略。F# 编译器自动使代码泛型,这种功能称为自动泛型化(automatic generalization)。在第五和第六章,我们将学习更多有关泛型函数与自动泛型化的内容。

清单 4.3 中的最后一个命令[2],为在清单 4.4 中的测试铺平了道路,那为什么不止一次输入测试数据呢?为了测试这个函数,先计算出和,最后,计算值为 123 的记录所占的百分比。因为我们想要获得精确结果(21.24%),因此调用函数 float,把整数转换为浮点数。

 

转换和解析数字

 

F# 是一种 .NET 语言,因此它使用这个平台上可用的数值类型的标准集。下面的清单显示了我们将要用到的最有用的类型,可以看到,.NET 的类名以斜体表示,F# 使用的简称放在括号中:

Int32,UInt32 (int,uint32): 标准的 32 位整数类型;F# 中,文字写作:42 (有符号)或 42u (无符号);也有 16 位和 64 位的变体,对于 16 位 (int16,uint16),写作 42s 和 42us,64 位 (int64,uint64)写作 1 L 或 64 位的 1UL。

Double, Single (float, float32):表示双精度和单精度浮点数;文字分别写作 3.14 和 3.14f。注意,在这里 F# 和 C# 之间是有区别的:在 C# 中的 double,在 F# 中叫 float;在 C# 中的float 在 F# 中叫 float32。

SByte, Byte (sbyte, byte):有符号和无符号的 8 位整数;文字写作 1y (有符号)和 1uy (无符号。

■ Decimal (decimal):十进制浮点类型,适合财务计算需要很多位整数和小数位数。文字写作 3.14M。

BigInteger (bigint):表示任意大小的整数类型。这是 .NET 4.0 中的新类型,由 System.Numerics 命名空间提供;F# 的早期版本包含了这个类型的自己实现,因此,在 Visual Studio 2008 中开发早期版本的 .NET 框架应用程序时,可以使用。在 F# 中,这种类型的文字写作 1I。

与 C# 不同,F# 编译器在不同的数字类型之间,即使在精度不会丢失的情况下,也不插入自动转换;F # 也不使用类型转换(type-cast)语法进行显式转换,因此,所有的转换都必须写成函数调用的形式。F# 库提供一组转换函数,通常与 F# 中目标类型的名称相同。下面是几个最有用的转换函数:

int :将任意数字转换为整数;该函数是多态的(polymorphic),因此,可以处理不同的参数类型。例如,将浮点值转换为整数,可以写成int 3.14;将字节值转换为整数,写成int 42uy。

float, float32 :将数字转换为双精度或单精度浮点数;float 对应于.NET 的 Double 类型,float32 对应于 .NET 的 Single 类型,有时令人困惑。

这些函数也可以用于将字符串转换为数字。如果需要更多地控制转换,例如,指定区域(culture)信息,可以使用 Parse 方法。此方法是System 命名空间中的 .NET 类,相当于数值类型。例如,要把字符串转换成整数,可以写成 Int32.Parse("42")。此方法在转换失败时会将抛出异常,因此,还有一个方法 TryParse。使用此方法,可以很容易测试转换是否成功,该方法返回布尔值标记,并通过输出参数给出解析后的数值;但在 F# 中,我们还有更简单的方法可以访问,我们将在第五章详细讨论。可以看到,这种用法很简单:

 

let (succ, num) = Int32.TryParse (str)

if succ then Console.Write("Succeeded:{0}", num)

else Console.Write("Failed")

 

这并不是使用 F# 和 .NET 处理数字的全面参考,我们只讨论了最常用的数值类型和函数。要详细了解,请参阅标准的 .NET 参考或 F# 在线参考 [F# 网站]。

 

在清单 4.4 中,我们最后计算了一个项占测试数据集的百分比的等式。这是 F# 迭代开发的另一个示例,因为,这正是我们在下一节所需要的等式。我们在隔离情况下尝试写出了这个计算中较难的部分,这样,可以在下一节使用。代码首先从文件中读数据,然后,使用这个等式作为代码的基础,输出数据集到控制台。

0 0
原创粉丝点击