Bagikan melalui


Daftar

Daftar dalam F# adalah serangkaian elemen yang diurutkan dan tidak dapat diubah dengan jenis yang sama. Untuk melakukan operasi dasar pada daftar, gunakan fungsi dalam modul Daftar.

Membuat dan Menginisialisasi Daftar

Anda dapat menentukan daftar dengan secara eksplisit mencantumkan elemen, dipisahkan oleh titik koma dan diapit dalam tanda kurung siku, seperti yang ditunjukkan pada baris kode berikut.

let list123 = [ 1; 2; 3 ]

Anda juga dapat menempatkan pemisah garis di antara elemen, dalam hal ini titik koma bersifat opsional. Sintaks terakhir dapat menghasilkan kode yang lebih mudah dibaca ketika ekspresi inisialisasi elemen lebih panjang, atau ketika Anda ingin menyertakan komentar untuk setiap elemen.

let list123 = [ 1; 2; 3 ]

Biasanya, semua elemen daftar harus berjenis yang sama. Pengecualian adalah bahwa daftar di mana elemen ditentukan untuk menjadi jenis dasar dapat memiliki elemen yang merupakan jenis turunan. Dengan demikian, berikut ini dapat diterima, karena keduanya Button dan CheckBox berasal dari Control.

let myControlList: Control list = [ new Button(); new CheckBox() ]

Anda juga dapat menentukan elemen daftar dengan menggunakan rentang yang ditunjukkan oleh bilangan bulat yang dipisahkan oleh operator rentang (..), seperti yang ditunjukkan dalam kode berikut.

let list1 = [ 1..10 ]

Daftar kosong ditentukan oleh sepasang tanda kurung siku tanpa apa pun di antaranya.

// An empty list.
let listEmpty = []

Anda juga dapat menggunakan ekspresi urutan untuk membuat daftar. Lihat Ekspresi Urutan untuk informasi selengkapnya. Misalnya, kode berikut membuat daftar kuadrat bilangan bulat dari 1 hingga 10.

let listOfSquares = [ for i in 1..10 -> i * i ]

Operator untuk Bekerja dengan Daftar

Anda dapat melampirkan elemen ke daftar dengan menggunakan :: operator (kontra). Jika list1 adalah [2; 3; 4], kode berikut dibuat list2 sebagai [100; 2; 3; 4].

let list2 = 100 :: list1

Anda dapat menggabungkan daftar yang memiliki jenis yang kompatibel dengan menggunakan @ operator, seperti dalam kode berikut. Jika list1 adalah [2; 3; 4] dan list2 adalah [100; 2; 3; 4], kode ini dibuat list3 sebagai [2; 3; 4; 100; 2; 3; 4].

let list3 = list1 @ list2

Fungsi untuk melakukan operasi pada daftar tersedia dalam modul Daftar.

Karena daftar di F# tidak dapat diubah, operasi modifikasi apa pun menghasilkan daftar baru alih-alih memodifikasi daftar yang ada.

Daftar dalam F# diimplementasikan sebagai daftar yang ditautkan senyap, yang berarti bahwa operasi yang hanya mengakses kepala daftar adalah O(1), dan akses elemen adalah O(n).

Karakteristik

Jenis daftar mendukung properti berikut:

Harta benda Tipe Deskripsi
Kepala 'T Elemen pertama.
Kosong 'T list Properti statis yang mengembalikan daftar kosong dari jenis yang sesuai.
Kosong bool true jika daftar tidak memiliki elemen.
Item 'T Elemen pada indeks yang ditentukan (berbasis nol).
Panjang int Jumlah elemen.
Tail 'T list Daftar tanpa elemen pertama.

Berikut ini adalah beberapa contoh penggunaan properti ini.

let list1 = [ 1; 2; 3 ]

// Properties
printfn "list1.IsEmpty is %b" (list1.IsEmpty)
printfn "list1.Length is %d" (list1.Length)
printfn "list1.Head is %d" (list1.Head)
printfn "list1.Tail.Head is %d" (list1.Tail.Head)
printfn "list1.Tail.Tail.Head is %d" (list1.Tail.Tail.Head)
printfn "list1.Item(1) is %d" (list1.Item(1))

Menggunakan Daftar

Pemrograman dengan daftar memungkinkan Anda melakukan operasi kompleks dengan sejumlah kecil kode. Bagian ini menjelaskan operasi umum pada daftar yang penting untuk pemrograman fungsional.

Rekursi dengan Daftar

Daftar secara unik cocok untuk teknik pemrograman rekursif. Pertimbangkan operasi yang harus dilakukan pada setiap elemen daftar. Anda dapat melakukan ini secara rekursif dengan mengoperasikan kepala daftar dan kemudian meneruskan ekor daftar, yang merupakan daftar yang lebih kecil yang terdiri dari daftar asli tanpa elemen pertama, kembali lagi ke tingkat rekursi berikutnya.

Untuk menulis fungsi rekursif seperti itu, Anda menggunakan operator kontra (::) dalam pencocokan pola, yang memungkinkan Anda memisahkan kepala daftar dari ekor.

Contoh kode berikut menunjukkan cara menggunakan pencocokan pola untuk mengimplementasikan fungsi rekursif yang melakukan operasi pada daftar.

let rec sum list =
    match list with
    | head :: tail -> head + sum tail
    | [] -> 0

Kode sebelumnya berfungsi dengan baik untuk daftar kecil, tetapi untuk daftar yang lebih besar, kode tersebut dapat meluapkan tumpukan. Kode berikut meningkatkan kode ini dengan menggunakan argumen akumulator, teknik standar untuk bekerja dengan fungsi rekursif. Penggunaan argumen akumulator membuat fungsi ekor rekursif, yang menghemat ruang tumpukan.

let sum list =
    let rec loop list acc =
        match list with
        | head :: tail -> loop tail (acc + head)
        | [] -> acc

    loop list 0

Fungsi RemoveAllMultiples ini adalah fungsi rekursif yang mengambil dua daftar. Daftar pertama berisi angka yang kelipatannya akan dihapus, dan daftar kedua adalah daftar untuk menghapus angka. Kode dalam contoh berikut menggunakan fungsi rekursif ini untuk menghilangkan semua angka non-prime dari daftar, meninggalkan daftar angka utama sebagai hasilnya.

let IsPrimeMultipleTest n x = x = n || x % n <> 0

let rec RemoveAllMultiples listn listx =
    match listn with
    | head :: tail -> RemoveAllMultiples tail (List.filter (IsPrimeMultipleTest head) listx)
    | [] -> listx


let GetPrimesUpTo n =
    let max = int (sqrt (float n))
    RemoveAllMultiples [ 2..max ] [ 1..n ]

printfn "Primes Up To %d:\n %A" 100 (GetPrimesUpTo 100)

Outputnya adalah sebagai berikut:

Primes Up To 100:
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71; 73; 79; 83; 89; 97]

Fungsi Modul

Modul Daftar menyediakan fungsi yang mengakses elemen daftar. Elemen kepala adalah yang tercepat dan term mudah diakses. Gunakan properti Head atau fungsi modul List.head. Anda dapat mengakses ekor daftar dengan menggunakan properti Tail atau fungsi List.tail . Untuk menemukan elemen menurut indeks, gunakan fungsi List.nth . List.nth melintasi daftar. Oleh karena itu, itu adalah O(n). Jika kode Anda sering digunakan List.nth , Anda mungkin ingin mempertimbangkan untuk menggunakan array alih-alih daftar. Akses elemen dalam array adalah O(1).

Operasi Boolean pada Daftar

Fungsi List.isEmpty menentukan apakah daftar memiliki elemen apa pun.

Fungsi List.exists menerapkan pengujian Boolean ke elemen daftar dan mengembalikan true jika ada elemen yang memenuhi pengujian. List.exists2 serupa tetapi beroperasi pada pasangan elemen berturut-turut dalam dua daftar.

Kode berikut menunjukkan penggunaan List.exists.

// Use List.exists to determine whether there is an element of a list satisfies a given Boolean expression.
// containsNumber returns true if any of the elements of the supplied list match
// the supplied number.
let containsNumber number list = List.exists (fun elem -> elem = number) list
let list0to3 = [0 .. 3]
printfn "For list %A, contains zero is %b" list0to3 (containsNumber 0 list0to3)

Outputnya adalah sebagai berikut:

For list [0; 1; 2; 3], contains zero is true

Contoh berikut menunjukkan penggunaan List.exists2.

// Use List.exists2 to compare elements in two lists.
// isEqualElement returns true if any elements at the same position in two supplied
// lists match.
let isEqualElement list1 list2 = List.exists2 (fun elem1 elem2 -> elem1 = elem2) list1 list2
let list1to5 = [ 1 .. 5 ]
let list5to1 = [ 5 .. -1 .. 1 ]
if (isEqualElement list1to5 list5to1) then
    printfn "Lists %A and %A have at least one equal element at the same position." list1to5 list5to1
else
    printfn "Lists %A and %A do not have an equal element at the same position." list1to5 list5to1

Outputnya adalah sebagai berikut:

Lists [1; 2; 3; 4; 5] and [5; 4; 3; 2; 1] have at least one equal element at the same position.

Anda dapat menggunakan List.forall jika Anda ingin menguji apakah semua elemen daftar memenuhi kondisi.

let isAllZeroes list = List.forall (fun elem -> elem = 0.0) list
printfn "%b" (isAllZeroes [0.0; 0.0])
printfn "%b" (isAllZeroes [0.0; 1.0])

Outputnya adalah sebagai berikut:

true
false

Demikian pula, List.forall2 menentukan apakah semua elemen dalam posisi yang sesuai dalam dua daftar memenuhi ekspresi Boolean yang melibatkan setiap pasangan elemen.

let listEqual list1 list2 = List.forall2 (fun elem1 elem2 -> elem1 = elem2) list1 list2
printfn "%b" (listEqual [0; 1; 2] [0; 1; 2])
printfn "%b" (listEqual [0; 0; 0] [0; 1; 0])

Outputnya adalah sebagai berikut:

true
false

Urutkan Operasi pada Daftar

Daftar pengurutan fungsi List.sort, List.sortBy, dan List.sortWith . Fungsi pengurutan menentukan mana dari ketiga fungsi yang akan digunakan. List.sort menggunakan perbandingan umum default. Perbandingan generik menggunakan operator global berdasarkan fungsi perbandingan generik untuk membandingkan nilai. Ini bekerja secara efisien dengan berbagai jenis elemen, seperti jenis numerik sederhana, tuple, rekaman, serikat yang diskriminasi, daftar, array, dan jenis apa pun yang mengimplementasikan System.IComparable. Untuk jenis yang mengimplementasikan System.IComparable, perbandingan System.IComparable.CompareTo() umum menggunakan fungsi . Perbandingan generik juga berfungsi dengan string, tetapi menggunakan urutan pengurutan independen budaya. Perbandingan generik tidak boleh digunakan pada jenis yang tidak didukung, seperti jenis fungsi. Selain itu, performa perbandingan generik default adalah yang terbaik untuk jenis terstruktur kecil; untuk jenis terstruktur yang lebih besar yang perlu sering dibandingkan dan diurutkan, pertimbangkan untuk menerapkan System.IComparable dan memberikan implementasi System.IComparable.CompareTo() metode yang efisien.

List.sortBy mengambil fungsi yang mengembalikan nilai yang digunakan sebagai kriteria pengurutan, dan List.sortWith mengambil fungsi perbandingan sebagai argumen. Dua fungsi terakhir ini berguna ketika Anda bekerja dengan jenis yang tidak mendukung perbandingan, atau ketika perbandingan membutuhkan semantik perbandingan yang lebih kompleks, seperti dalam kasus string yang sadar budaya.

Contoh berikut menunjukkan penggunaan List.sort.

let sortedList1 = List.sort [1; 4; 8; -2; 5]
printfn "%A" sortedList1

Outputnya adalah sebagai berikut:

[-2; 1; 4; 5; 8]

Contoh berikut menunjukkan penggunaan List.sortBy.

let sortedList2 = List.sortBy (fun elem -> abs elem) [1; 4; 8; -2; 5]
printfn "%A" sortedList2

Outputnya adalah sebagai berikut:

[1; -2; 4; 5; 8]

Contoh berikutnya menunjukkan penggunaan List.sortWith. Dalam contoh ini, fungsi compareWidgets perbandingan kustom digunakan untuk terlebih dahulu membandingkan satu bidang dari jenis kustom, lalu yang lain ketika nilai bidang pertama sama.

type Widget = { ID: int; Rev: int }

let compareWidgets widget1 widget2 =
   if widget1.ID < widget2.ID then -1 else
   if widget1.ID > widget2.ID then 1 else
   if widget1.Rev < widget2.Rev then -1 else
   if widget1.Rev > widget2.Rev then 1 else
   0

let listToCompare = [
    { ID = 92; Rev = 1 }
    { ID = 110; Rev = 1 }
    { ID = 100; Rev = 5 }
    { ID = 100; Rev = 2 }
    { ID = 92; Rev = 1 }
    ]

let sortedWidgetList = List.sortWith compareWidgets listToCompare
printfn "%A" sortedWidgetList

Outputnya adalah sebagai berikut:

[{ID = 92;
Rev = 1;}; {ID = 92;
Rev = 1;}; {ID = 100;
Rev = 2;}; {ID = 100;
Rev = 5;}; {ID = 110;
Rev = 1;}]

Operasi Pencarian pada Daftar

Banyak operasi pencarian didukung untuk daftar. List.find yang paling sederhana memungkinkan Anda menemukan elemen pertama yang cocok dengan kondisi tertentu.

Contoh kode berikut menunjukkan penggunaan List.find untuk menemukan angka pertama yang dapat dibagi 5 dalam daftar.

let isDivisibleBy number elem = elem % number = 0
let result = List.find (isDivisibleBy 5) [ 1 .. 100 ]
printfn "%d " result

Hasilnya adalah 5.

Jika elemen harus diubah terlebih dahulu, panggil List.pick, yang mengambil fungsi yang mengembalikan opsi, dan mencari nilai opsi pertama yaitu Some(x). Alih-alih mengembalikan elemen, List.pick mengembalikan hasilnya x. Jika tidak ada elemen yang cocok yang ditemukan, List.pick lemparkan System.Collections.Generic.KeyNotFoundException. Kode berikut menunjukkan penggunaan List.pick.

let valuesList = [ ("a", 1); ("b", 2); ("c", 3) ]

let resultPick = List.pick (fun elem ->
                    match elem with
                    | (value, 2) -> Some value
                    | _ -> None) valuesList
printfn "%A" resultPick

Outputnya adalah sebagai berikut:

"b"

Grup operasi pencarian lain, List.tryFind dan fungsi terkait, mengembalikan nilai opsi. Fungsi mengembalikan elemen pertama dari daftar yang memenuhi kondisi jika elemen seperti itu List.tryFind ada, tetapi nilai None opsi jika tidak. Variasi List.tryFindIndex mengembalikan indeks elemen, jika ditemukan, bukan elemen itu sendiri. Fungsi-fungsi ini diilustrasikan dalam kode berikut.

let list1d = [1; 3; 7; 9; 11; 13; 15; 19; 22; 29; 36]
let isEven x = x % 2 = 0
match List.tryFind isEven list1d with
| Some value -> printfn "The first even value is %d." value
| None -> printfn "There is no even value in the list."

match List.tryFindIndex isEven list1d with
| Some value -> printfn "The first even value is at position %d." value
| None -> printfn "There is no even value in the list."

Outputnya adalah sebagai berikut:

The first even value is 22.
The first even value is at position 8.

Operasi Aritmatika pada Daftar

Operasi aritmatika umum seperti jumlah dan rata-rata dibangun ke dalam modul Daftar. Untuk bekerja dengan List.sum, jenis elemen daftar harus mendukung + operator dan memiliki nilai nol. Semua jenis aritmatika bawaan memenuhi kondisi ini. Untuk bekerja dengan List.average, jenis elemen harus mendukung pembagian tanpa sisanya, yang mengecualikan jenis integral tetapi memungkinkan jenis titik mengambang. Fungsi List.sumBy dan List.averageBy mengambil fungsi sebagai parameter, dan hasil fungsi ini digunakan untuk menghitung nilai untuk jumlah atau rata-rata.

Kode berikut menunjukkan penggunaan List.sum, , List.sumBydan List.average.

// Compute the sum of the first 10 integers by using List.sum.
let sum1 = List.sum [1 .. 10]

// Compute the sum of the squares of the elements of a list by using List.sumBy.
let sum2 = List.sumBy (fun elem -> elem*elem) [1 .. 10]

// Compute the average of the elements of a list by using List.average.
let avg1 = List.average [0.0; 1.0; 1.0; 2.0]

printfn "%f" avg1

Outputnya adalah 1.000000.

Kode berikut menunjukkan penggunaan List.averageBy.

let avg2 = List.averageBy (fun elem -> float elem) [1 .. 10]
printfn "%f" avg2

Outputnya adalah 5.5.

Daftar dan Tuple

Daftar yang berisi tuple dapat dimanipulasi oleh fungsi zip dan unzip. Fungsi-fungsi ini menggabungkan dua daftar nilai tunggal ke dalam satu daftar tuple atau memisahkan satu daftar tuple menjadi dua daftar nilai tunggal. Fungsi List.zip paling sederhana mengambil dua daftar elemen tunggal dan menghasilkan satu daftar pasangan tuple. Versi lain, List.zip3, mengambil tiga daftar elemen tunggal dan menghasilkan satu daftar tuple yang memiliki tiga elemen. Contoh kode berikut menunjukkan penggunaan List.zip.

let list1 = [ 1; 2; 3 ]
let list2 = [ -1; -2; -3 ]
let listZip = List.zip list1 list2
printfn "%A" listZip

Outputnya adalah sebagai berikut:

[(1, -1); (2, -2); (3; -3)]

Contoh kode berikut menunjukkan penggunaan List.zip3.

let list3 = [ 0; 0; 0]
let listZip3 = List.zip3 list1 list2 list3
printfn "%A" listZip3

Outputnya adalah sebagai berikut:

[(1, -1, 0); (2, -2, 0); (3, -3, 0)]

Versi unzip yang sesuai, List.unzip dan List.unzip3, mengambil daftar tuple dan mengembalikan daftar dalam tuple, di mana daftar pertama berisi semua elemen yang pertama di setiap tuple, dan daftar kedua berisi elemen kedua dari setiap tuple, dan sebagainya.

Contoh kode berikut menunjukkan penggunaan List.unzip.

let lists = List.unzip [(1,2); (3,4)]
printfn "%A" lists
printfn "%A %A" (fst lists) (snd lists)

Outputnya adalah sebagai berikut:

([1; 3], [2; 4])
[1; 3] [2; 4]

Contoh kode berikut menunjukkan penggunaan List.unzip3.

let listsUnzip3 = List.unzip3 [(1,2,3); (4,5,6)]
printfn "%A" listsUnzip3

Outputnya adalah sebagai berikut:

([1; 4], [2; 5], [3; 6])

Beroperasi pada Elemen Daftar

F# mendukung berbagai operasi pada elemen daftar. Yang paling sederhana adalah List.iter, yang memungkinkan Anda memanggil fungsi pada setiap elemen daftar. Variasi termasuk List.iter2, yang memungkinkan Anda melakukan operasi pada elemen dua daftar, List.iteri, yang seperti List.iter kecuali bahwa indeks setiap elemen diteruskan sebagai argumen ke fungsi yang dipanggil untuk setiap elemen, dan List.iteri2, yang merupakan kombinasi dari fungsionalitas List.iter2 dan List.iteri. Contoh kode berikut mengilustrasikan fungsi-fungsi ini.

let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
List.iter (fun x -> printfn "List.iter: element is %d" x) list1
List.iteri(fun i x -> printfn "List.iteri: element %d is %d" i x) list1
List.iter2 (fun x y -> printfn "List.iter2: elements are %d %d" x y) list1 list2
List.iteri2 (fun i x y ->
                printfn "List.iteri2: element %d of list1 is %d element %d of list2 is %d"
                  i x i y)
            list1 list2

Outputnya adalah sebagai berikut:

List.iter: element is 1
List.iter: element is 2
List.iter: element is 3
List.iteri: element 0 is 1
List.iteri: element 1 is 2
List.iteri: element 2 is 3
List.iter2: elements are 1 4
List.iter2: elements are 2 5
List.iter2: elements are 3 6
List.iteri2: element 0 of list1 is 1; element 0 of list2 is 4
List.iteri2: element 1 of list1 is 2; element 1 of list2 is 5
List.iteri2: element 2 of list1 is 3; element 2 of list2 is 6

Fungsi lain yang sering digunakan yang mengubah elemen daftar adalah List.map, yang memungkinkan Anda menerapkan fungsi ke setiap elemen daftar dan memasukkan semua hasil ke dalam daftar baru. List.map2 dan List.map3 adalah variasi yang mengambil beberapa daftar. Anda juga dapat menggunakan List.mapi dan List.mapi2, jika, selain elemen , fungsi perlu diteruskan indeks dari setiap elemen. Satu-satunya perbedaan antara List.mapi2 dan List.mapi adalah yang List.mapi2 berfungsi dengan dua daftar. Contoh berikut mengilustrasikan List.map.

let list1 = [1; 2; 3]
let newList = List.map (fun x -> x + 1) list1
printfn "%A" newList

Outputnya adalah sebagai berikut:

[2; 3; 4]

Contoh berikut menunjukkan penggunaan List.map2.

let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
let sumList = List.map2 (fun x y -> x + y) list1 list2
printfn "%A" sumList

Outputnya adalah sebagai berikut:

[5; 7; 9]

Contoh berikut menunjukkan penggunaan List.map3.

let newList2 = List.map3 (fun x y z -> x + y + z) list1 list2 [2; 3; 4]
printfn "%A" newList2

Outputnya adalah sebagai berikut:

[7; 10; 13]

Contoh berikut menunjukkan penggunaan List.mapi.

let newListAddIndex = List.mapi (fun i x -> x + i) list1
printfn "%A" newListAddIndex

Outputnya adalah sebagai berikut:

[1; 3; 5]

Contoh berikut menunjukkan penggunaan List.mapi2.

let listAddTimesIndex = List.mapi2 (fun i x y -> (x + y) * i) list1 list2
printfn "%A" listAddTimesIndex

Outputnya adalah sebagai berikut:

[0; 7; 18]

List.collect seperti List.map, kecuali bahwa setiap elemen menghasilkan daftar dan semua daftar ini digabungkan ke dalam daftar akhir. Dalam kode berikut, setiap elemen daftar menghasilkan tiga angka. Ini semua dikumpulkan ke dalam satu daftar.

let collectList = List.collect (fun x -> [for i in 1..3 -> x * i]) list1
printfn "%A" collectList

Outputnya adalah sebagai berikut:

[1; 2; 3; 2; 4; 6; 3; 6; 9]

Anda juga dapat menggunakan List.filter, yang mengambil kondisi Boolean dan menghasilkan daftar baru yang hanya terdiri dari elemen yang memenuhi kondisi yang diberikan.

let evenOnlyList = List.filter (fun x -> x % 2 = 0) [1; 2; 3; 4; 5; 6]

Daftar yang dihasilkan adalah [2; 4; 6].

Kombinasi peta dan filter, List.select memungkinkan Anda mengubah dan memilih elemen secara bersamaan. List.choose menerapkan fungsi yang mengembalikan opsi ke setiap elemen daftar, dan mengembalikan daftar baru hasil untuk elemen saat fungsi mengembalikan nilai Someopsi .

Kode berikut menunjukkan penggunaan List.choose untuk memilih kata kapital dari daftar kata.

let listWords = [ "and"; "Rome"; "Bob"; "apple"; "zebra" ]
let isCapitalized (string1:string) = System.Char.IsUpper string1[0]
let results = List.choose (fun elem ->
    match elem with
    | elem when isCapitalized elem -> Some(elem + "'s")
    | _ -> None) listWords
printfn "%A" results

Outputnya adalah sebagai berikut:

["Rome's"; "Bob's"]

Beroperasi pada Beberapa Daftar

Daftar dapat digabungkan bersama-sama. Untuk menggabungkan dua daftar menjadi satu, gunakan List.append. Untuk menggabungkan lebih dari dua daftar, gunakan List.concat.

let list1to10 = List.append [1; 2; 3] [4; 5; 6; 7; 8; 9; 10]
let listResult = List.concat [ [1; 2; 3]; [4; 5; 6]; [7; 8; 9] ]
List.iter (fun elem -> printf "%d " elem) list1to10
printfn ""
List.iter (fun elem -> printf "%d " elem) listResult

Operasi Lipat dan Pindai

Beberapa operasi daftar melibatkan saling ketergantungan antara semua elemen daftar. Operasi lipatan dan pemindaian seperti List.iter dan List.map di mana Anda memanggil fungsi pada setiap elemen, tetapi operasi ini menyediakan parameter tambahan yang disebut akumulator yang membawa informasi melalui komputasi.

Gunakan List.fold untuk melakukan penghitungan pada daftar.

Contoh kode berikut menunjukkan penggunaan List.fold untuk melakukan berbagai operasi.

Daftar dilalui; akumulator acc adalah nilai yang diteruskan saat penghitungan berlanjut. Argumen pertama mengambil akumulator dan elemen daftar, dan mengembalikan hasil sementara dari perhitungan untuk elemen daftar tersebut. Argumen kedua adalah nilai awal akumulator.

let sumList list = List.fold (fun acc elem -> acc + elem) 0 list
printfn "Sum of the elements of list %A is %d." [ 1 .. 3 ] (sumList [ 1 .. 3 ])

// The following example computes the average of a list.
let averageList list = (List.fold (fun acc elem -> acc + float elem) 0.0 list / float list.Length)

// The following example computes the standard deviation of a list.
// The standard deviation is computed by taking the square root of the
// sum of the variances, which are the differences between each value
// and the average.
let stdDevList list =
    let avg = averageList list
    sqrt (List.fold (fun acc elem -> acc + (float elem - avg) ** 2.0 ) 0.0 list / float list.Length)

let testList listTest =
    printfn "List %A average: %f stddev: %f" listTest (averageList listTest) (stdDevList listTest)

testList [1; 1; 1]
testList [1; 2; 1]
testList [1; 2; 3]

// List.fold is the same as to List.iter when the accumulator is not used.
let printList list = List.fold (fun acc elem -> printfn "%A" elem) () list
printList [0.0; 1.0; 2.5; 5.1 ]

// The following example uses List.fold to reverse a list.
// The accumulator starts out as the empty list, and the function uses the cons operator
// to add each successive element to the head of the accumulator list, resulting in a
// reversed form of the list.
let reverseList list = List.fold (fun acc elem -> elem::acc) [] list
printfn "%A" (reverseList [1 .. 10])

Versi fungsi-fungsi ini yang memiliki digit dalam nama fungsi beroperasi pada lebih dari satu daftar. Misalnya, List.fold2 melakukan komputasi pada dua daftar.

Contoh berikut menunjukkan penggunaan List.fold2.

// Use List.fold2 to perform computations over two lists (of equal size) at the same time.
// Example: Sum the greater element at each list position.
let sumGreatest list1 list2 = List.fold2 (fun acc elem1 elem2 ->
                                              acc + max elem1 elem2) 0 list1 list2

let sum = sumGreatest [1; 2; 3] [3; 2; 1]
printfn "The sum of the greater of each pair of elements in the two lists is %d." sum

List.fold dan List.scan berbeda dalam yang List.fold mengembalikan nilai akhir parameter tambahan, tetapi List.scan mengembalikan daftar nilai perantara (bersama dengan nilai akhir) dari parameter tambahan.

Masing-masing fungsi ini mencakup variasi terbalik, misalnya, List.foldBack, yang berbeda dalam urutan di mana daftar dilalui dan urutan argumen. Selain itu, List.fold dan List.foldBack memiliki variasi, List.fold2 dan List.foldBack2, yang mengambil dua daftar dengan panjang yang sama. Fungsi yang dijalankan pada setiap elemen dapat menggunakan elemen yang sesuai dari kedua daftar untuk melakukan beberapa tindakan. Jenis elemen dari dua daftar dapat berbeda, seperti dalam contoh berikut, di mana satu daftar berisi jumlah transaksi untuk rekening bank, dan daftar lainnya berisi jenis transaksi: deposit atau penarikan.

// Discriminated union type that encodes the transaction type.
type Transaction =
    | Deposit
    | Withdrawal

let transactionTypes = [Deposit; Deposit; Withdrawal]
let transactionAmounts = [100.00; 1000.00; 95.00 ]
let initialBalance = 200.00

// Use fold2 to perform a calculation on the list to update the account balance.
let endingBalance = List.fold2 (fun acc elem1 elem2 ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2)
                                initialBalance
                                transactionTypes
                                transactionAmounts
printfn "%f" endingBalance

Untuk perhitungan seperti penjumlahan, List.fold dan List.foldBack memiliki efek yang sama karena hasilnya tidak bergantung pada urutan traversal. Dalam contoh berikut, List.foldBack digunakan untuk menambahkan elemen dalam daftar.

let sumListBack list = List.foldBack (fun elem acc -> acc + elem) list 0
printfn "%d" (sumListBack [1; 2; 3])

// For a calculation in which the order of traversal is important, fold and foldBack have different
// results. For example, replacing fold with foldBack in the listReverse function
// produces a function that copies the list, rather than reversing it.
let copyList list = List.foldBack (fun elem acc -> elem::acc) list []
printfn "%A" (copyList [1 .. 10])

Contoh berikut mengembalikan ke contoh rekening bank. Kali ini jenis transaksi baru ditambahkan: perhitungan bunga. Saldo akhir sekarang tergantung pada urutan transaksi.

type Transaction2 =
    | Deposit
    | Withdrawal
    | Interest

let transactionTypes2 = [Deposit; Deposit; Withdrawal; Interest]
let transactionAmounts2 = [100.00; 1000.00; 95.00; 0.05 / 12.0 ]
let initialBalance2 = 200.00

// Because fold2 processes the lists by starting at the head element,
// the interest is calculated last, on the balance of 1205.00.
let endingBalance2 = List.fold2 (fun acc elem1 elem2 ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2
                                | Interest -> acc * (1.0 + elem2))
                                initialBalance2
                                transactionTypes2
                                transactionAmounts2
printfn "%f" endingBalance2


// Because foldBack2 processes the lists by starting at end of the list,
// the interest is calculated first, on the balance of only 200.00.
let endingBalance3 = List.foldBack2 (fun elem1 elem2 acc ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2
                                | Interest -> acc * (1.0 + elem2))
                                transactionTypes2
                                transactionAmounts2
                                initialBalance2
printfn "%f" endingBalance3

Fungsi List.reduce agak seperti List.fold dan List.scan, kecuali bahwa alih-alih melewati akumulator terpisah, List.reduce mengambil fungsi yang mengambil dua argumen dari jenis elemen alih-alih hanya satu, dan salah satu argumen tersebut bertindak sebagai akumulator, yang berarti bahwa ia menyimpan hasil perantara dari komputasi. List.reduce dimulai dengan beroperasi pada dua elemen daftar pertama, lalu menggunakan hasil operasi bersama dengan elemen berikutnya. Karena tidak ada akumulator terpisah yang memiliki jenisnya sendiri, List.reduce hanya dapat digunakan sebagai pengganti List.fold ketika akumulator dan jenis elemen memiliki jenis yang sama. Kode berikut menunjukkan penggunaan List.reduce. List.reduce melempar pengecualian jika daftar yang disediakan tidak memiliki elemen.

Dalam kode berikut, panggilan pertama ke ekspresi lambda diberi argumen 2 dan 4, dan mengembalikan 6, dan panggilan berikutnya diberi argumen 6 dan 10, sehingga hasilnya adalah 16.

let sumAList list =
    try
        List.reduce (fun acc elem -> acc + elem) list
    with
       | :? System.ArgumentException as exc -> 0

let resultSum = sumAList [2; 4; 10]
printfn "%d " resultSum

Mengonversi Antara Daftar dan Tipe Koleksi Lainnya

Modul ini List menyediakan fungsi untuk mengonversi ke dan dari urutan dan array. Untuk mengonversi ke atau dari urutan, gunakan List.toSeq atau List.ofSeq. Untuk mengonversi ke atau dari array, gunakan List.toArray atau List.ofArray.

Operasi Tambahan

Untuk informasi tentang operasi tambahan pada daftar, lihat topik referensi pustaka Modul Daftar.

Lihat juga