【F#从入门到实战】02. F#数组常见用法

举报
jackwangcumt 发表于 2021/07/14 17:16:56 2021/07/14
【摘要】 F#数组是固定大小的、从0开始、可变的连续数据元素集合,这些元素属于同一类型。一般来说,数组以一维数组和二维数组比较常用。在F#中还有一种列表类型(也是同类型的元素),它和数组的定义比较类似,但是它是不可变的对象,即一旦列表定义好后,我们无法修改特定索引上的元素值,而只能读取。但F#数组却可以进行元素的读取和写入。

       欢迎大家来到【F#从入门到实战】,在这里我将分享关于F#编程语言的系列文章,带大家一起去学习和成长,并探索函数编程语言F#这个有趣的世界。所有文章都会结合示例代码和笔者的经验进行讲解,真心想把十余年的IT经验分享给大家,希望对您有所帮助,文章中也定有不足之处,请海涵!本系统文章将从F#基本语法入手,逐步通过自定义类型来实现数学表达式的各种常见解析操作,如对表达式进行求值、化简、展开、求导和求积分等。此系统博文也是了解和实现一个简易的计算机代数系统的基础。

      下面给出【F#从入门到实战】系统专题文章的目录:

【F#从入门到实战】01. F#语言快速入门 
【F#从入门到实战】02. F#数组常见用法   
【F#从入门到实战】03. F#自定义操作符 
【F#从入门到实战】04. F#5.0新特征总结 
【F#从入门到实战】05. F#表达式求值     
【F#从入门到实战】06. F#表达式化简    
【F#从入门到实战】07. F#表达式展开    
【F#从入门到实战】08. F#大整数阶乘    
【F#从入门到实战】09. F#表达式求导   
【F#从入门到实战】10. F#表达式积分   
【F#从入门到实战】11. F#库FParsec入门  
【F#从入门到实战】12. F#库FParsec解析表达式   
【F#从入门到实战】13. F#库FParsec实现求导符号计算   
【F#从入门到实战】14. F#实现分部积分法   

     下面将正式开始本文的介绍:  
     根据官方定义,F#数组是固定大小的、从0开始、可变的连续数据元素集合,这些元素属于同一类型。一般来说,数组以一维数组和二维数组比较常用。在F#中还有一种列表类型(也是同类型的元素),它和数组的定义比较类似,但是它是不可变的对象,即一旦列表定义好后,我们无法修改特定索引上的元素值,而只能读取。但F#数组却可以进行元素的读取和写入。

//列表
let a = [1;2;3]
//不可变
a.[0] <- 1 //error
///////////////////////////
//数组 int[]
let a = [|1;2;3|]
//可变
a.[0] <- 1

      下面给出一维数组和二维数组的常用用法示例:

module ArrayDemo
    let test() = 
        //[|1; 2; 3|]
        let arr = [| 1; 2; 3 |]
        printfn "%A" arr
        let arr = [| for i in 1 .. 10 -> 2 * i |]
        //length=10
        printfn "length=%d" arr.Length
        //[|2; 4; 6; 8; 10; 12; 14; 16; 18; 20|]
        printfn "%A" arr
        //2
        printfn "%d" arr.[0]
        //[|2; 4; 6|]
        printfn "%A" arr.[0..2]
        //[|2; 4; 6|]
        printfn "%A" arr.[..2]
        //[|6; 8; 10; 12; 14; 16; 18; 20|]
        printfn "%A" arr.[2..]
        //修改值
        arr.[0] <- 0
        //[|0; 4; 6|]
        printfn "%A" arr.[0..2]
        let arr = Array.create 7 0.0
        //[|0.0; 0.0; 0.0; 0.0; 0.0; 0.0; 0.0|]
        printfn "%A" arr
        let arr2 = Array.sub arr 0 2
        //[|0.0; 0.0|]
        printfn "%A" arr2
        let arr2 = Array.append [| 1; 2; 3|] [| 4; 5|]
        printfn "%A" arr2
        let arr2 =Array.choose(fun e -> if e % 2 = 0 then
                                                    Some(e)
                                                else
                                                    None) arr2
        //[|2; 4|]
        printfn "%A" arr2
        let arr2 =Array.collect (fun e -> [| 2*e+1 |] ) arr2
        //[|5; 9|]
        printfn "%A" arr2
        let arr2 = Array.concat [ [|0..3|] ; arr2 ]
        //[|0; 1; 2; 3; 5; 9|]
        printfn "%A" arr2
        let arr2 = Array.filter (fun e -> e % 2 = 1) arr2
        //[|1; 3; 5; 9|]
        printfn "%A" arr2
        let arr2 = Array.rev arr2
        //[|9; 5; 3; 1|]
        printfn "%A" arr2
        let amap = Array.map2 (fun e1 e2 ->  e1*e2 ) [| 1;2;3 |] [| 1;2;3 |]
        //[|1; 4; 9|]
        printfn "%A" amap
        let s = Array.sum amap
        //14
        printfn "%d" s
        let tarr = Array.chunkBySize 2 [| 1;2;3;4;5;6 |]
        //[|[|1; 2|]; [|3; 4|]; [|5; 6|]|]
        printfn "%A" tarr
        ////////////////////////////
        let arr2d = array2D  [ [ 1; 0]; [0; 1] ]
        (* [[1; 0]
        [0; 1]] *)
        printfn "%A" arr2d
        let arr2d = Array2D.init 3 2 (fun i j -> 0)
        (* [[0; 0]
        [0; 0]
        [0; 0]] *)
        printfn "%A" arr2d
        let arr2d = array2D  [ [1;2;3]; [4;5;6] ]
        //[[4; 5; 6]]
        printfn "%A" arr2d.[1.. , * ]
        (*[[2; 3]
        [5; 6]]*)
        printfn "%A" arr2d.[* , 1..2 ]
        //[|2; 5|]
        printfn "%A" arr2d.[* , 1]
        //1,2,3
        Array.iter (fun e -> printf "%d," e) [|1;2;3|]
        //Array.iter (fun e -> printf "%A" e) arr2d //Error
        //2
        printfn "%d" (Array2D.length1 arr2d)
        //3
        printfn "%d" (Array2D.length2 arr2d)
        //1,2,3,4,5,6,
        Array2D.iter (fun e -> printf "%d," e) arr2d
        printfn ""
        (*[0,0]= 1
        [0,1]= 2
        [0,2]= 3
        [1,0]= 4
        [1,1]= 5
        [1,2]= 6
        *)
        Array2D.iteri (fun i j e -> printfn "[%d,%d]= %d" i j e) arr2d
        //二维数组
        let m1 = array2D  [ [1;2;3]; [4;5;6] ] 
        let m2 = array2D  [ [7;8;9]; [10;11;12] ] 
        let rlen = Array2D.length1 m1
        let clen = Array2D.length2 m1
        let m3 = Array2D.init rlen clen (fun i j -> 0)
        for i = 0 to rlen - 1 do 
            for j = 0 to clen - 1 do
                m3.[i,j] <- m1.[i,j] +  m2.[i,j]
        (*
        [[8; 10; 12]
        [14; 16; 18]]
        *)
        printfn "%A" m3

      其中的 printfn "%A" arr 可以打印出数组arr的内容。%A即代表数组类型。arr.Length 可以获取一维数组元素的长度。数组的元素可以通过 .[index]来获取,注意前面有一个dot符号,即arr.[0] 可以获取到一维数组arr的第一个元素(下标为0)。另外,还可以给定范围,获取多个元素,即arr.[0..2] 可以获取3个元素,即下标为0,1,2的元素。此外,通过类似 获取元素的用法,还可以省略开始下标或者结束下标,如arr.[..2]

     数组的创建还可以通过Array.create方法来实现,如let arr = Array.create 7 0.0则创建一个长度为7,初始值为0.0的一维数组,即[|0.0; 0.0; 0.0; 0.0; 0.0; 0.0; 0.0|]。Array.append [| 1; 2; 3|] [| 4; 5|] 方法可以将两个数组进行合并,值为[| 1; 2; 3; 4; 5|] 。Array.concat方法可以将一个二维数组转换成一个一维数组,即Array.concat [ [|0..3|] ; [|5; 9|] ] 生成[|0; 1; 2; 3; 5; 9|] 。

     而Array.map2 (fun e1 e2 ->  e1*e2 ) [| 1;2;3 |] [| 1;2;3 |] 中的Array.map2可以将两个长度一致的一维数组进行映射,并生成新的数组,返回[|1; 4; 9|]。Array.sum 方法则可以将一维数组中的元素进行求和操作。Array.chunkBySize 2 [| 1;2;3;4;5;6 |]则将一维数组按照2个一组进行拆分,即生成[|[|1; 2|]; [|3; 4|]; [|5; 6|]|] 。

     对于二维数组,则可以通过array2D进行定义,如 let arr2d = array2D  [ [ 1; 0]; [0; 1] ] 或者通过Array2D.init方法进行初始化,如Array2D.init 3 2 (fun i j -> 0)。对于一个arr2d值为[ [1;2;3]; [4;5;6] ] 的二维数组,arr2d.[1.. , * ] 可以获取到[[4; 5; 6]] 。而下面的示例就可以实现二维数组的和,比如矩阵求和,类似于矩阵求和:

let m1 = array2D  [ [1;2;3]; [4;5;6] ] 
let m2 = array2D  [ [7;8;9]; [10;11;12] ] 
let rlen = Array2D.length1 m1
let clen = Array2D.length2 m1
let m3 = Array2D.init rlen clen (fun i j -> 0)
for i = 0 to rlen - 1 do 
     for j = 0 to clen - 1 do
           m3.[i,j] <- m1.[i,j] +  m2.[i,j]
(*
   [[8; 10; 12]
   [14; 16; 18]]
*)
printfn "%A" m3

这里注意,二维数组有两个长度属性,即Array2D.length1代表行数,而Array2D.length2代表列数。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。