Daftar

Daftar di F# adalah kumpulan elemen yang berurutan dan tidak berubah dari jenis yang sama. Untuk melakukan operasi dasar pada daftar, gunakan fungsi dalam Modul daftar.

Membuat dan Menginsialisasi Daftar

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

let list123 = [ 1; 2; 3 ]

Anda juga dapat menempatkan jeda garis di antara elemen, bisa menggunakan titik koma. Sintaks yang 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 sama. Pengecualian diberikan pada daftar yang berisi elemen yang ditentukan untuk menjadi jenis dasar dapat memiliki elemen yang merupakan jenis turunan. Oleh karena itu, hasil berikut ini dapat diterima, karena Button dan CheckBox keduanya 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 isi.

// 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 Menggunakan Daftar

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

let list2 = 100 :: list1

Anda dapat menggabungkan daftar yang berjenis kompatibel dengan menggunakan operator @, seperti dalam kode berikut. Jika list1 adalah [2; 3; 4] dan list2 adalah [100; 2; 3; 4], kode ini membuat 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 berubah, setiap operasi modifikasi tidak memodifikasi daftar yang ada, melainkan menghasilkan daftar baru.

Daftar dalam F# diimplementasikan sebagai daftar yang ditautkan secara tunggal, artinya, operasi yang hanya mengakses bagian atas daftar adalah O(1), dan akses elemen adalah O(n).

Properti

Jenis daftar mendukung properti berikut:

Properti Tipe Deskripsi
Kepala 'T Elemen pertama.
Kosong 'T list Properti statis yang memunculkan daftar kosong pada jenis yang sesuai.
IsEmpty bool true jika daftar tidak memiliki elemen.
Benda 'T Elemen pada indeks yang ditentukan (berbasis nol).
Panjang int Jumlah elemen.
Ekor 'T list Daftar tanpa elemen pertama.

Berikut adalah beberapa contoh menggunakan 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 untuk melakukan operasi yang kompleks dengan sedikit kode. Bagian ini menjelaskan operasi umum pada daftar yang penting untuk pemrograman fungsional.

Rekursi dengan Daftar

Daftar cocok secara unik untuk teknik pemrograman rekursif. Pertimbangkan operasi yang harus dilakukan pada setiap elemen daftar. Anda dapat melakukannya secara rekursif dengan beroperasi di bagian atas daftar dan kemudian melewati bagian akhir daftar. Akhiran daftar merupakan daftar yang lebih kecil yang terdiri dari daftar asli tanpa elemen pertama,kemudian kembali lagi ke tingkat rekursi berikutnya.

Untuk menulis fungsi rekursif seperti itu, gunakan operator kontra (::) dalam pencocokan pola, yang memungkinkan Anda memisahkan bagian atas daftar dan bagian bawah.

Contoh kode berikut menunjukkan cara menggunakan pencocokan pola untuk menerapkan 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 pada daftar kecil, tetapi untuk daftar yang lebih besar, tumpukannya bisa meluap. Kode berikut meningkatkan kode ini dengan menggunakan argumen akumulator, yaitu teknik standar agar berfungsi dengan fungsi rekursif. Penggunaan argumen akumulator membuat fungsi bagian akhir daftar rekursif, yang mana 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 adalah fungsi rekursif yang mengambil dua daftar. Daftar pertama berisi angka-angka yang kelipatannya akan dihapus, dan daftar kedua adalah daftar untuk menghapus angka. Kode dalam contoh berikut menggunakan fungsi rekursif ini untuk menghilangkan semua bilangan non-prima dari daftar, menghasilkan daftar bilangan prima.

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 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 termudah untuk diakses. Gunakan properti Head atau fungsi modul List.head. Anda dapat mengakses bagian akhir daftar dengan menggunakan properti Tail atau fungsi List.tail. Untuk menemukan elemen berdasarkan indeks, gunakan fungsi List.nth. List.nth melintasi daftar. Oleh karena itu, aksesnya adalah O(n). Jika kode Anda sering menggunakan List.nth, pertimbangkan untuk menggunakan array, bukan daftar. Akses elemen dalam array adalah O(1).

Operasi Boolean dalam Daftar

Fungsi List.isEmpty menentukan apakah daftar memiliki elemen atau tidak.

Fungsi List.exists menerapkan pengujian Boolean ke elemen daftar dan memunculkan true jika ada elemen yang memenuhi pengujian. List.exists2 juga 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 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 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 ingin menguji apakah semua elemen daftar memenuhi persyaratan.

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 sebagai berikut:

true
false

Demikian pula, List.forall2 menentukan apakah semua elemen dalam posisi yang sesuai dalam dua daftar memenuhi ungkapan 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 sebagai berikut:

true
false

Mengurutkan Operasi pada Daftar

Daftar urutan fungsi List.sort, List.sortBy, dan List.sortWith. Fungsi pengurutan menentukan salah satu dari ketiga fungsi ini yang akan digunakan. List.sort menggunakan perbandingan generik default. Perbandingan generik menggunakan operator global berdasarkan fungsi perbandingan generik untuk membandingkan nilai. Perbandingan ini berfungsi secara efisien dengan berbagai jenis elemen, seperti jenis numerik sederhana, tupel, rekaman, gabungan terdiskriminasi, daftar, array, dan jenis apa pun yang mengimplementasikan System.IComparable. Untuk jenis yang mengimplementasikan System.IComparable, perbandingan generik menggunakan fungsi System.IComparable.CompareTo(). Perbandingan generik juga berfungsi dengan string, tetapi menggunakan urutan sortir yang independen secara kultur. 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; sedangkan untuk jenis terstruktur yang lebih besar yang perlu sering dibandingkan dan diurutkan, sebaiknya terapkan System.IComparable dan memberikan implementasi metode System.IComparable.CompareTo() yang efisien.

List.sortBy mengambil fungsi yang memunculkan 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 kultur.

Contoh berikut menunjukkan penggunaan List.sort.

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

Outputnya 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 sebagai berikut:

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

Contoh berikut menunjukkan penggunaan List.sortWith. Dalam contoh ini, compareWidgets fungsi perbandingan kustom digunakan untuk membandingkan terlebih dahulu satu bidang dari jenis kustom, lalu bidang 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 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. Yang paling sederhana, List.find, memungkinkan Anda menemukan elemen pertama yang cocok dengan kondisi tertentu.

Contoh kode berikut menunjukkan penggunaan List.find untuk menemukan angka pertama yang dapat dibagi dengan 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 memunculkan opsi, dan mencari nilai opsi pertama, yaitu Some(x). Alih-alih memunculkan elemen, List.pick memunculkan hasilnya x. Jika tidak ada elemen yang cocok yang ditemukan, List.pick mengeluarkan 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 sebagai berikut:

"b"

Grup operasi pencarian lain, List.tryFind dan fungsi terkait, memunculkan nilai opsi. Fungsi List.tryFind memunculkan elemen pertama dari daftar yang memenuhi kondisi jika terdapat elemen seperti itu, tetapi jika tidak,maka akan memunculkan nilai opsi None. Variasi List.tryFindIndex memunculkan indeks elemen (jika ada), bukan memunculkan elemen itu sendiri. Fungsi-fungsi ini ditunjukkan 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 sebagai berikut:

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

Operasi Aritmatika dalam 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 persayaratan ini. Untuk bekerja dengan List.average, jenis elemen harus mendukung pembagian tanpa sisa. Hal ini mengecualikan jenis integral tetapi mengizinkan jenis bilangan 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.sumBy, dan 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 Tupel

Daftar yang berisi tupel dapat dimanipulasi dengan fungsi zip dan unzip. Fungsi-fungsi ini menggabungkan dua daftar nilai tunggal menjadi satu daftar tupel atau memisahkan satu daftar tupel menjadi dua daftar nilai tunggal. Fungsi List.zip yang paling sederhana mengambil dua daftar elemen tunggal dan menghasilkan satu daftar pasangan tupel. Versi lain, List.zip3, mengambil tiga daftar elemen tunggal dan menghasilkan satu daftar tupel 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 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 sebagai berikut:

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

Versi unzip yang sesuai, List.unzip dan List.unzip3, mengambil daftar tupel dan memunculkan daftar dalam tupel, di mana daftar pertama berisi semua elemen yang pertama di setiap tupel, dan daftar kedua berisi elemen kedua dari setiap tupel, dan seterusnya.

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 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 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. Variasinya termasuk List.iter2, yang memungkinkan Anda melakukan operasi pada elemen dari dua daftar. Daftar pertama List.iteri, yang seperti List.iter bedanya indeks setiap elemen diteruskan sebagai argumen ke fungsi yang dipanggil untuk setiap elemen, dan daftar kedua List.iteri2, yang merupakan kombinasi dari fungsionalitas List.iter2 dan List.iteri. Contoh kode berikut menggambarkan 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 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. Fungsi ini memungkinkan Anda menerapkan fungsi ke setiap elemen daftar dan memasukkan semua hasilnya ke dalam daftar baru. List.map2 dan List.map3 adalah variasi yang mengambil beberapa daftar. Selain elemen, jika fungsi perlu meneruskan indeks dari setiap elemen, Anda juga dapat menggunakan List.mapi dan List.mapi2. Satu-satunya perbedaan antara List.mapi2 dan List.mapi adalah List.mapi2 yang brfungsi 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 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 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 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 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 sebagai berikut:

[0; 7; 18]

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

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

Outputnya sebagai berikut:

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

Anda juga dapat menggunakan List.filter, yang mengambil persyaratan Boolean dan menghasilkan daftar baru yang hanya terdiri dari elemen yang memenuhi persyaratan 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 memunculkan opsi ke setiap elemen daftar, dan memunculkan daftar baru hasil elemen saat fungsi mengembalikan nilai opsi Some.

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 sebagai berikut:

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

Beroperasi pada Beberapa Daftar

Daftar dapat digabungkan bersama. 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 saling bergantung antara semua elemen daftar. Operasi lipat dan pindai mirip seperti List.iter dan List.map, di mana Anda memanggil fungsi pada setiap elemen,bedanya operasi ini memberikan parameter tambahan yang disebut accumulator 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 ini dilewati; acc akumulator adalah nilai yang diteruskan saat perhitungan berlanjut. Argumen pertama mengambil akumulator dan elemen daftar, dan memunculkan hasil perhitungan sementara untuk elemen daftar itu. 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 dengan List.fold yang memunculkan nilai akhir parameter tambahan, tetapi List.scan memunculkan daftar nilai perantara (bersama dengan nilai akhir) dari parameter tambahan.

Masing-masing fungsi ini mencakup variasi terbalik, misalnya, List.foldBack, yang berbeda pada urutan di mana daftar dilalui dan urutan argumen. Selain itu, List.fold dan List.foldBack memiliki variasi, yaitu 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 kedua berisi jenis transaksi: setoran 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 memunculkan contoh rekening bank. Kali ini, jenis transaksi baru ditambahkan: perhitungan bunga. Saldo akhir saat ini bergantung 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 mirip seperti List.fold dan List.scan, bedanya tidak melewati akumulator terpisah, List.reduce mengambil fungsi yang mengambil dua argumen dari jenis elemen alih-alih hanya satu. Salah satu argumen tersebut bertindak sebagai akumulator, yang 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 jenis sendiri, List.reduce dapat digunakan sebagai ganti List.fold hanya ketika akumulator dan jenis elemen memiliki jenis yang sama. Kode berikut menunjukkan penggunaan List.reduce. List.reduce memberikan pengecualian jika daftar yang disediakan tidak memiliki elemen.

Dalam kode berikut, panggilan pertama ke ekspresi lambda diberikan argumen 2 dan 4, dan memunculkan 6. Panggilan berikutnya diberikan argumen 6 dan 10, 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 Jenis Koleksi Lainnya

Modul List menyediakan fungsi untuk mengonversi ke dan dari kedua urutan serta 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