10.2.3.1 以函式方式使用陣列
我們先來看乙個 f# 的例子,這是兩個f# 庫處理陣列的重要的高階函式,然後,用 c# 實現相同的功能。清單 10.12 的中指令碼,先用隨機數初始化乙個陣列,然後,計算出它們的平方。
清單 10.12 處理陣列的函式式方法(f# interactive)
> let rnd = new system.random();;
val rnd : system.random
> let numbers = array.init 5 (fun _-> rnd.next(10));; [1]
val numbers : int array = [|1; 0; 7; 2; 2|]
> let squares = numbers |> array.map(fun n -> (n, n*n));; [2]
val squares : (int * int) array = [| ... |]
> for sq in squares do | 從結果陣列中輸出元組
printf "%a " sq;; |
(1, 1) (0, 0) (7, 49) (2, 4) (2, 4)
我們使用的第乙個高階函式是 array.init [1],類似於在清單 10.2 中討論過的 list.int,它使用給定的函式初始化陣列;第二個函式是 array.map [2],與我們熟悉的 list.map 函式功能相同,在這個例子中,我們用它來建立乙個元組陣列,結果的每個元素包含原始的整數及其平方。
關鍵在於,這個例子中,我們在整個**中都沒有使用賦值運算子。第乙個操作構造新的陣列,第二個操作沒有修改這個陣列,而是返回另乙個新建立的陣列。雖然,陣列是可變的,但是,我們在**中,使用高階函式來處理,根本不改變它們。如果我們使用函式式列表,這個例子一樣能執行。
在陣列和列表之間選擇
我們已經看到,陣列和列表的使用方式是相似的,因此,就有乙個什麼時候選擇哪乙個的問題。第一點要考慮的是型別是否可變。函式程式設計極力強調資料型別是不可變的,我們將在下一章和第十四章看到的實際例子,說明為什麼這是值得的。我們能夠以函式方式處理陣列,但在保證程式的正確性方面,列表要更強一些。
另一點要考慮的是,對於某些操作,一種資料型別比另外的資料型別,更容易或更有效。在列表的前面追加元素,是比複製陣列的內容到稍大一點的新陣列中,要更容易。另一方面,對於隨機訪問,陣列更好。處理陣列的操作往往更快。我們可以看乙個簡單的使用 #time 指令的例子:
let l = [ 1 .. 100000 ]
let a = [| 1 .. 100000 |];;
for i in 1 .. 100 do ß takes 885ms
ignore(l |> list.map (fun n -> n));;
for i in 1 .. 100 do ß takes 109ms
ignore(a |> array.map (fun n -> n));;
如果需要高效處理大型資料集,通常陣列更好。在大多數情況下,首要目的應該使用清晰和簡單的**,函式式列表通常會有更好的可讀性。
我們前面的例子表明,雖然可以使用陣列上提供的一些基本操作,但仍經常要自己寫一些類似的操作。清單 10.13 是乙個函式,以函式風格處理陣列:引數為乙個陣列,根據輸入計算並返回乙個新的陣列。這個函式常用於「平滑」或「模糊」值陣列,在新陣列中的每個值與原有的值和它兩側的值相對應。
清單 10.13 模糊化陣列的函式式方法 (f#)
let blurarray (arr:int) =
letres = array.create arr.length 0
res.[0] <- (arr.[0] + arr.[1]) / 2 | [1]
res.[arr.length-1] <- (arr.[arr.length-2] + arr.[arr.length-1]) / 2 |
for iin 1 .. arr.length - 2 do [1]
res.[i] <- (arr.[i-1] + arr.[i] + arr.[i+1]) / 3
res函式首先建立用於儲存結果的陣列,大小與輸入陣列相同;然後,計算出新陣列的第乙個元素的值和最後乙個元素的值[1](這是兩個元素的平均值),這些值的計算與陣列的其餘部分是分開的,因為它們是邊界,模式與其餘部分不在一樣;最後,遍歷陣列中間的元素,取三個值的平均值,作為結果寫入新的陣列中。
函式內部使用可變模式(mutation),在開始時,建立的陣列用零填充,後來,把計算值寫到這個陣列中。這種可變性從外部是不可見的,到呼叫者能夠使用陣列的時候,我們已經完成了變。當我們使用這個函式時,完全可以放心地使用所有通常的函式技術:
> let ar = array.init 10 (fun _ ->rnd.next(20));; ß 初始化隨機數組
val ar : int = [|14; 14; 4; 16; 1; 15;5; 14; 7; 13|]
> ar |> blurarray;; ß 對陣列進行模糊化一次
val it : int = [|14; 10; 11; 7; 10; 7;11; 8; 11; 10|]
> ar |> blurarray |> blurarray|> blurarray;; ß 使用管道對陣列進行模糊化三次
val it : int = [|7; 8; 9; 9; 9; 9; 9; 9;8; 8|]
blurarray 函式的型別是int -> int,這使它成為可組合的。第二個命令,我們使用管道運算子,把隨機生成的陣列作為輸入,傳送給函式,f# 互動控制台自動輸出結果。最後乙個命令表明,我們還能夠連續呼叫函式幾次,同樣的方法,我們在列表的 map 或 filter 操作上使用過。
我們可能想擴充套件這個例子用來處理影象,把 blurarray 函式轉換成為真正的、能處理點陣圖的模糊濾鏡。如果想嘗試一下,還需要使用 array2d 模組,它有處理二維陣列的函式,以及讀取、寫入圖形資料的 .net 點陣圖類,比如 getpixel 和 setpixel。到第十四章,我們還會回來到這個問題,討論使用並行化更有效地執行操作。
在看過在 f# 中優美地使用陣列以後,我們將把注意力放回到 c# 中。所有的 c# 程式設計師都知道使用陣列的基本知識,而我們感興趣的是,能使用函式風格寫出處理陣列的 c# **。
10 2 3 2 在 C 中以函式風格使用陣列
10.2.3.2 在 c 中以函式風格使用陣列 由於有了 linq to object,在 c 3.0 中,我們已經可以使用許多函式結構來處理陣列。大多數 linq 運算子不返回陣列 如果在陣列上呼叫 enumerable.select,結果將返回 ienumerable。在某些情況下,我們還是願意...
Spring以註解方式使用aop
7.spring以註解方式使用 xmlversion 1.0 encoding utf 8 beans xmlns xsi xmlns xmlns context xmlns aop xsi schemalocation spring beans 4.2.xsd spring context 4.2...
JavaScript陣列的三種定義方式以及使用
陣列的定義 1.陣列的屬性以及方法 1 常用屬性 length 返回陣列中元素的個數 2 常用方法 方 法說 明join 將陣列中的元素組合成字串 reverse 顛倒陣列元素的順序,使第乙個元素成為最後乙個,而最後乙個元素成為第乙個 sort 對陣列元素進行排序 陣列的常用方法 function ...