Urutan

Urutan adalah serangkaian elemen logis dari seluruh bagian jenis. Urutan sangat berguna ketika Anda memiliki kumpulan data yang besar dan teratur tetapi tidak selalu perlu menggunakan semua elemen. Elemen urutan individu dihitung hanya sesuai kebutuhan, sehingga urutan dapat memberikan performa yang lebih baik daripada daftar ketika tidak semua elemen digunakan. Urutan diwakili oleh jenis seq<'T>, yang merupakan alias untuk IEnumerable<T>. Oleh karena itu, jenis .NET apa pun yang mengimplementasikan antarmuka IEnumerable<T> dapat digunakan sebagai urutan. Modul Seq menyediakan dukungan untuk manipulasi yang melibatkan urutan.

Ekspresi Urutan

Ekspresi urutan adalah ekspresi yang mengevaluasi urutan. Ekspresi urutan dapat berupa sejumlah bentuk. Bentuk yang paling sederhana menentukan rentang. Misalnya, seq { 1 .. 5 } membuat urutan yang berisi lima elemen, termasuk titik akhir 1 dan 5. Anda juga dapat menentukan kenaikan (atau penurunan) antara dua periode ganda. Misalnya, kode berikut membuat urutan kelipatan 10.

// Sequence that has an increment.
seq { 0..10..100 }

Ekspresi urutan terdiri dari ekspresi F# yang menghasilkan nilai-nilai urutan. Anda juga dapat menghasilkan nilai secara terprogram:

seq { for i in 1..10 -> i * i }

Sampel sebelumnya menggunakan operator ->, yang memungkinkan Anda menentukan ekspresi yang nilainya akan menjadi bagian dari urutan. Anda hanya dapat menggunakan -> jika setiap bagian kode yang mengikutinya dapat memunculkan nilai.

Atau, Anda dapat menentukan kata kunci do, dengan yield opsional yang mengikuti:

seq {
    for i in 1..10 do
        yield i * i
}

// The 'yield' is implicit and doesn't need to be specified in most cases.
seq {
    for i in 1..10 do
        i * i
}

Kode berikut menghasilkan daftar pasangan koordinat bersama dengan indeks ke dalam array yang mewakili grid. Perhatikan bahwa ekspresi for pertama memerlukan do agar ditentukan.

let (height, width) = (10, 10)

seq {
    for row in 0 .. width - 1 do
        for col in 0 .. height - 1 -> (row, col, row * width + col)
}

Ekspresi if yang digunakan dalam urutan adalah filter. Misalnya, untuk menghasilkan urutan bilangan prima saja, dengan asumsi Anda memiliki fungsi isprime jenis int -> bool, buat urutan sebagai berikut.

seq {
    for n in 1..100 do
        if isprime n then
            n
}

Seperti disebutkan sebelumnya, do diperlukan di sini karena tidak ada cabang else yang berjalan dengan if. Jika Anda mencoba menggunakan ->, Anda akan mendapatkan kesalahan yang mengatakan bahwa tidak semua cabang memunculkan nilai.

Kata kunci yield!

Terkadang, Anda ingin memasukkan urutan elemen ke dalam urutan lain. Untuk menyertakan urutan dalam urutan lain, Anda harus menggunakan kata kunci yield!:

// Repeats '1 2 3 4 5' ten times
seq {
    for _ in 1..10 do
        yield! seq { 1; 2; 3; 4; 5}
}

Cara berpikir yield! yang lain adalah meratakan urutan dalam kemudian mencakupnya dalam urutan yang berada di dalamnya.

Saat yield! digunakan dalam ekspresi, semua nilai tunggal lainnya harus menggunakan kata kunci yield:

// Combine repeated values with their values
seq {
    for x in 1..10 do
        yield x
        yield! seq { for i in 1..x -> i}
}

Contoh sebelumnya akan menghasilkan nilai x selain semua nilai dari 1 ke x untuk setiap x.

Contoh

Contoh pertama menggunakan ekspresi urutan yang berisi iterasi, filter, dan hasil untuk menghasilkan array. Kode ini mencetak urutan bilangan prima antara 1 dan 100 ke konsol.

// Recursive isprime function.
let isprime n =
    let rec check i =
        i > n / 2 || (n % i <> 0 && check (i + 1))

    check 2

let aSequence =
    seq {
        for n in 1..100 do
            if isprime n then
                n
    }

for x in aSequence do
    printfn "%d" x

Contoh berikut membuat tabel perkalian yang terdiri dari tupel tiga elemen, masing-masing terdiri dari dua faktor dan produk:

let multiplicationTable =
    seq {
        for i in 1..9 do
            for j in 1..9 -> (i, j, i * j)
    }

Contoh berikut menunjukkan penggunaan yield! untuk menggabungkan urutan individual ke dalam satu urutan akhir. Dalam hal ini, urutan untuk setiap subpohon dalam pohon biner digabungkan dalam fungsi rekursif untuk menghasilkan urutan akhir.

// Yield the values of a binary tree in a sequence.
type Tree<'a> =
    | Tree of 'a * Tree<'a> * Tree<'a>
    | Leaf of 'a

// inorder : Tree<'a> -> seq<'a>
let rec inorder tree =
    seq {
        match tree with
        | Tree(x, left, right) ->
            yield! inorder left
            yield x
            yield! inorder right
        | Leaf x -> yield x
    }

let mytree = Tree(6, Tree(2, Leaf(1), Leaf(3)), Leaf(9))
let seq1 = inorder mytree
printfn "%A" seq1

Menggunakan Urutan

Urutan mendukung banyak fungsi yang sama dengan daftar. Urutan juga mendukung operasi seperti pengelompokan dan penghitungan menggunakan fungsi pembuatan kunci. Urutan juga mendukung fungsi yang lebih beragam untuk mengekstraksi sub-urutan.

Banyak jenis data, seperti daftar, array, set, dan peta yang merupakan urutan secara implisit karena merupakan koleksi terbilang. Fungsi yang mengambil urutan sebagai argumen bekerja dengan salah satu jenis data F# umum, selain jenis data .NET apa pun yang mengimplementasikan System.Collections.Generic.IEnumerable<'T>. Bandingkan dengan fungsi yang mengambil daftar sebagai argumen, yang hanya dapat mengambil daftar. Jenis seq<'T> adalah singkatan jenis untuk IEnumerable<'T>. Artinya, setiap jenis yang mengimplementasikan System.Collections.Generic.IEnumerable<'T> umum, yang mencakup array, daftar, set, dan peta di F#, dan juga sebagian besar jenis koleksi .NET, bersifat kompatibel dengan jenis seq dan dapat digunakan di mana pun urutan tersebut diharapkan.

Fungsi Modul

Modul Seq di namespace layanan FSharp.Collections berisi fungsi untuk bekerja dengan urutan. Fungsi-fungsi ini bekerja dengan daftar, array, peta, dan juga set, karena semua jenis tersebut terbilang, dan oleh karena itu, dapat diperlakukan sebagai urutan.

Membuat Urutan

Anda dapat membuat urutan dengan menggunakan ekspresi urutan, seperti yang dijelaskan sebelumnya, atau dengan menggunakan fungsi tertentu.

Anda dapat membuat urutan kosong dengan menggunakan Seq.empty, atau Anda dapat membuat urutan hanya satu elemen tertentu dengan menggunakan Seq.singleton.

let seqEmpty = Seq.empty
let seqOne = Seq.singleton 10

Anda dapat menggunakan Seq.init untuk membuat urutan yang elemennya dibuat dengan menggunakan fungsi yang Anda sediakan. Anda juga menyediakan ukuran untuk urutannya. Fungsi ini mirip seperti List.init, bedanya adalah elemen tersebut tidak dibuat sampai Anda melakukan iterasi melalui urutan. Kode berikut menggambarkan penggunaan Seq.init.

let seqFirst5MultiplesOf10 = Seq.init 5 (fun n -> n * 10)
Seq.iter (fun elem -> printf "%d " elem) seqFirst5MultiplesOf10

Outputnya adalah

0 10 20 30 40

Dengan menggunakan Fungsi Seq.ofArray and Seq.ofList<'T>, Anda dapat membuat urutan dari array dan daftar. Namun, Anda juga dapat mengonversi array dan daftar ke urutan dengan menggunakan operator transmisi. Kedua teknik ini ditunjukkan dalam kode berikut.

// Convert an array to a sequence by using a cast.
let seqFromArray1 = [| 1 .. 10 |] :> seq<int>

// Convert an array to a sequence by using Seq.ofArray.
let seqFromArray2 = [| 1 .. 10 |] |> Seq.ofArray

Dengan menggunakan Seq.cast, Anda dapat membuat urutan dari kumpulan yang dikonversi secara implisit, seperti yang didefinisikan dalam System.Collections. Koleksi yang dikonversi secara implisit tersebut memiliki jenis elemen System.Object dan dicacah dengan menggunakan jenis non-generik System.Collections.Generic.IEnumerable&#96;1. Kode berikut menunjukkan penggunaan Seq.cast untuk mengonversi System.Collections.ArrayList menjadi urutan.

open System

let arr = ResizeArray<int>(10)

for i in 1 .. 10 do
    arr.Add(10)

let seqCast = Seq.cast arr

Anda dapat menentukan urutan tak terbatas dengan menggunakan fungsi Seq.initInfinite. Untuk urutan seperti itu, sediakan fungsi yang menghasilkan setiap elemen dari indeks elemen. Urutan tak terbatas dimungkinkan karena adanya lazy evaluation, yaitu elemen dibuat sesuai kebutuhan dengan memanggil fungsi yang Anda tentukan. Contoh kode berikut menghasilkan urutan tak terbatas dari bilangan titik mengambang, yaitu seri bolak-balik dari kuadrat bilangan bulat berturut-turut.

let seqInfinite =
    Seq.initInfinite (fun index ->
        let n = float (index + 1)
        1.0 / (n * n * (if ((index + 1) % 2 = 0) then 1.0 else -1.0)))

printfn "%A" seqInfinite

Seq.unfold menghasilkan urutan dari fungsi komputasi yang mengambil status dan mengubahnya untuk menghasilkan setiap elemen berikutnya dalam urutan. Status ini hanyalah nilai yang digunakan untuk menghitung setiap elemen, dan dapat berubah saat setiap elemen dihitung. Argumen kedua ke Seq.unfold adalah nilai awal yang digunakan untuk memulai urutan. Seq.unfold menggunakan jenis opsi untuk status ini, yang memungkinkan Anda mengakhiri urutan dengan memunculkan nilai None. Kode berikut menunjukkan dua contoh urutan, seq1 dan fib, yang dihasilkan oleh operasi unfold. Yang pertama, seq1, hanyalah urutan sederhana dengan angka hingga 20. Yang kedua, fib, menggunakan unfold untuk menghitung urutan Fibonacci. Karena setiap elemen dalam urutan Fibonacci adalah jumlah dari dua angka Fibonacci sebelumnya, nilai status adalah tupel yang terdiri dari dua angka sebelumnya dalam urutan. Nilai awal adalah (0,1), dua angka pertama dalam urutan tersebut.

let seq1 =
    0 // Initial state
    |> Seq.unfold (fun state ->
        if (state > 20) then
            None
        else
            Some(state, state + 1))

printfn "The sequence seq1 contains numbers from 0 to 20."

for x in seq1 do
    printf "%d " x

let fib =
    (0, 1)
    |> Seq.unfold (fun state ->
        let cur, next = state
        if cur < 0 then  // overflow
            None
        else
            let next' = cur + next
            let state' = next, next'
            Some (cur, state') )

printfn "\nThe sequence fib contains Fibonacci numbers."
for x in fib do printf "%d " x

Outputnya sebagai berikut:

The sequence seq1 contains numbers from 0 to 20.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

The sequence fib contains Fibonacci numbers.

0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 

Kode berikut adalah contoh yang menggunakan banyak fungsi modul urutan yang dijelaskan di sini untuk menghasilkan dan menghitung nilai urutan tak terbatas. Kode ini mungkin perlu waktu beberapa menit untuk dijalankan.

// generateInfiniteSequence generates sequences of floating point
// numbers. The sequences generated are computed from the fDenominator
// function, which has the type (int -> float) and computes the
// denominator of each term in the sequence from the index of that
// term. The isAlternating parameter is true if the sequence has
// alternating signs.
let generateInfiniteSequence fDenominator isAlternating =
    if (isAlternating) then
        Seq.initInfinite (fun index ->
            1.0 /(fDenominator index) * (if (index % 2 = 0) then -1.0 else 1.0))
    else
        Seq.initInfinite (fun index -> 1.0 /(fDenominator index))

// The harmonic alternating series is like the harmonic series
// except that it has alternating signs.
let harmonicAlternatingSeries = generateInfiniteSequence (fun index -> float index) true

// This is the series of reciprocals of the odd numbers.
let oddNumberSeries = generateInfiniteSequence (fun index -> float (2 * index - 1)) true

// This is the series of recipocals of the squares.
let squaresSeries = generateInfiniteSequence (fun index -> float (index * index)) false

// This function sums a sequence, up to the specified number of terms.
let sumSeq length sequence =
    (0, 0.0)
    |>
    Seq.unfold (fun state ->
        let subtotal = snd state + Seq.item (fst state + 1) sequence
        if (fst state >= length) then
            None
        else
            Some(subtotal, (fst state + 1, subtotal)))

// This function sums an infinite sequence up to a given value
// for the difference (epsilon) between subsequent terms,
// up to a maximum number of terms, whichever is reached first.
let infiniteSum infiniteSeq epsilon maxIteration =
    infiniteSeq
    |> sumSeq maxIteration
    |> Seq.pairwise
    |> Seq.takeWhile (fun elem -> abs (snd elem - fst elem) > epsilon)
    |> List.ofSeq
    |> List.rev
    |> List.head
    |> snd

// Compute the sums for three sequences that converge, and compare
// the sums to the expected theoretical values.
let result1 = infiniteSum harmonicAlternatingSeries 0.00001 100000
printfn "Result: %f  ln2: %f" result1 (log 2.0)

let pi = Math.PI
let result2 = infiniteSum oddNumberSeries 0.00001 10000
printfn "Result: %f pi/4: %f" result2 (pi/4.0)

// Because this is not an alternating series, a much smaller epsilon
// value and more terms are needed to obtain an accurate result.
let result3 = infiniteSum squaresSeries 0.0000001 1000000
printfn "Result: %f pi*pi/6: %f" result3 (pi*pi/6.0)

Mencari dan Menemukan Elemen

Fungsionalitas dukungan urutan tersedia dengan daftar: Seq.exists, Seq.exists2, Seq.find, Seq.findIndex, Seq.pick, Seq.tryFind, dan Seq.tryFindIndex. Versi fungsi-fungsi yang tersedia untuk urutan ini mengevaluasi urutan sampai ke elemen yang sedang dicari saja. Misalnya, lihat Daftar.

Mendapatkan Sub-urutan

Seq.filter dan Seq.choose mirip seperti fungsi terkait yang tersedia untuk daftar, bedanya tidak terjadi pemfilteran dan pemilihan sampai elemen urutan dievaluasi.

Seq.truncate membuat urutan dari urutan lain, tetapi membatasi urutan ke sejumlah elemen tertentu. Seq.take membuat urutan baru yang hanya berisi sejumlah elemen tertentu dari awal urutan. Jika ada lebih sedikit elemen dalam urutan daripada yang ditentukan untuk diambil, Seq.take mengeluarkan System.InvalidOperationException. Perbedaan antara Seq.take dan Seq.truncate adalah Seq.truncate tidak menghasilkan kesalahan jika jumlah elemen lebih sedikit dari angka yang Anda tentukan.

Kode berikut menunjukkan perilaku dan perbedaan antara Seq.truncate dan Seq.take.

let mySeq = seq { for i in 1 .. 10 -> i*i }
let truncatedSeq = Seq.truncate 5 mySeq
let takenSeq = Seq.take 5 mySeq

let truncatedSeq2 = Seq.truncate 20 mySeq
let takenSeq2 = Seq.take 20 mySeq

let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn ""

// Up to this point, the sequences are not evaluated.
// The following code causes the sequences to be evaluated.
truncatedSeq |> printSeq
truncatedSeq2 |> printSeq
takenSeq |> printSeq
// The following line produces a run-time error (in printSeq):
takenSeq2 |> printSeq

Sebelum kesalahan terjadi, outputnya adalah sebagai berikut.

1 4 9 16 25
1 4 9 16 25 36 49 64 81 100
1 4 9 16 25
1 4 9 16 25 36 49 64 81 100

Dengan menggunakan Seq.takeWhile, Anda dapat menentukan fungsi predikat (fungsi Boolean) dan membuat urutan dari urutan lain yang terdiri dari elemen-elemen urutan asli yang predikatnya adalah true, tetapi berhentilah sebelum elemen pertama yang predikatnya memunculkan false. Seq.skip mengembalikan urutan yang melompati jumlah tertentu pada elemen pertama dari urutan lain dan memunculkan elemen yang tersisa. Seq.skipWhile memunculkan urutan yang melompati elemen pertama pada urutan lain selama predikat memunculkan true, lalu memunculkan elemen yang tersisa, dimulai dengan elemen pertama yang predikatnya memunculkan false.

Contoh kode berikut menunjukkan perilaku dan perbedaan antara Seq.takeWhile, Seq.skip, dan Seq.skipWhile.

// takeWhile
let mySeqLessThan10 = Seq.takeWhile (fun elem -> elem < 10) mySeq
mySeqLessThan10 |> printSeq

// skip
let mySeqSkipFirst5 = Seq.skip 5 mySeq
mySeqSkipFirst5 |> printSeq

// skipWhile
let mySeqSkipWhileLessThan10 = Seq.skipWhile (fun elem -> elem < 10) mySeq
mySeqSkipWhileLessThan10 |> printSeq

Outputnya sebagai berikut.

1 4 9
36 49 64 81 100
16 25 36 49 64 81 100

Mengubah Urutan

Seq.pairwise membuat urutan baru di mana elemen berturut-turut pada urutan input dikelompokkan ke dalam tupel.

let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn ""
let seqPairwise = Seq.pairwise (seq { for i in 1 .. 10 -> i*i })
printSeq seqPairwise

printfn ""
let seqDelta = Seq.map (fun elem -> snd elem - fst elem) seqPairwise
printSeq seqDelta

Seq.windowed mirip seperti Seq.pairwise, bedanya tidak menghasilkan urutan tuple, melainkan menghasilkan urutan array yang berisi salinan elemen yang berdekatan ( jendela) dari urutan. Tentukan jumlah elemen yang berdekatan yang Anda inginkan di setiap array.

Contoh kode berikut menunjukkan penggunaan Seq.windowed. Dalam hal ini, jumlah elemen di jendela adalah 3. Contohnya menggunakan printSeq, yang didefinisikan dalam contoh kode sebelumnya.

let seqNumbers = [ 1.0; 1.5; 2.0; 1.5; 1.0; 1.5 ] :> seq<float>
let seqWindows = Seq.windowed 3 seqNumbers
let seqMovingAverage = Seq.map Array.average seqWindows
printfn "Initial sequence: "
printSeq seqNumbers
printfn "\nWindows of length 3: "
printSeq seqWindows
printfn "\nMoving average: "
printSeq seqMovingAverage

Outputnya sebagai berikut.

Urutan awal:

1.0 1.5 2.0 1.5 1.0 1.5

Windows of length 3:
[|1.0; 1.5; 2.0|] [|1.5; 2.0; 1.5|] [|2.0; 1.5; 1.0|] [|1.5; 1.0; 1.5|]

Moving average:
1.5 1.666666667 1.5 1.333333333

Operasi dengan Beberapa Urutan

Seq.zip dan Seq.zip3 mengambil dua atau tiga urutan dan menghasilkan urutan tupel. Fungsi-fungsi ini sama seperti fungsi yang sesuai yang tersedia untuk daftar. Tidak ada fungsi yang sesuai untuk memisahkan satu urutan menjadi dua urutan atau lebih. Jika Anda memerlukan fungsionalitas ini untuk urutan, konversikan urutan tersebut ke daftar dan gunakan List.unzip.

Menyortir, Membandingkan, dan Mengelompokkan

Fungsi pengurutan yang didukung untuk daftar juga dapat digunakan untuk urutan. Termasuk Seq.sort dan Seq.sortBy. Fungsi-fungsi ini mengiterasi melalui seluruh urutan.

Bandingkan dua urutan dengan menggunakan fungsi Seq.compareWith. Fungsi ini membandingkan elemen berturut-turut secara bergantian, dan berhenti ketika bertemu dengan pasangan tidak setara pertama. Setiap elemen tambahan tidak berkontribusi pada perbandingan.

Kode berikut menunjukkan penggunaan Seq.compareWith.

let sequence1 = seq { 1 .. 10 }
let sequence2 = seq { 10 .. -1 .. 1 }

// Compare two sequences element by element.
let compareSequences =
    Seq.compareWith (fun elem1 elem2 ->
        if elem1 > elem2 then 1
        elif elem1 < elem2 then -1
        else 0)

let compareResult1 = compareSequences sequence1 sequence2
match compareResult1 with
| 1 -> printfn "Sequence1 is greater than sequence2."
| -1 -> printfn "Sequence1 is less than sequence2."
| 0 -> printfn "Sequence1 is equal to sequence2."
| _ -> failwith("Invalid comparison result.")

Pada kode sebelumnya, hanya elemen pertama yang dihitung dan diperiksa, dan hasilnya adalah -1.

Seq.countBy mengambil fungsi yang menghasilkan nilai yang disebut kunci untuk setiap elemen. Kunci dihasilkan untuk setiap elemen dengan memanggil fungsi ini pada setiap elemen. Kemudian Seq.countBy mengembalikan urutan yang berisi nilai kunci, dan hitungan jumlah elemen yang menghasilkan setiap nilai kunci.

let mySeq1 = seq { 1.. 100 }

let printSeq seq1 = Seq.iter (printf "%A ") seq1

let seqResult =
    mySeq1
    |> Seq.countBy (fun elem ->
        if elem % 3 = 0 then 0
        elif elem % 3 = 1 then 1
        else 2)

printSeq seqResult

Outputnya sebagai berikut.

(1, 34) (2, 33) (0, 33)

Output sebelumnya menunjukkan bahwa ada 34 elemen dari urutan asli menghasilkan kunci 1, 33 nilai yang menghasilkan kunci 2, dan 33 nilai yang menghasilkan kunci 0.

Anda dapat mengelompokkan elemen urutan dengan memanggil Seq.groupBy. Seq.groupBy mengambil urutan dan fungsi yang menghasilkan kunci dari elemen. Fungsi tersebut dijalankan pada setiap elemen urutan. Seq.groupBy memunculkan urutan tupel, di mana elemen pertama dari setiap tupel adalah kunci dan yang kedua adalah urutan elemen yang menghasilkan kunci tersebut.

Contoh kode berikut menunjukkan penggunaan Seq.groupBy untuk mempartisi urutan angka dari 1 hingga 100 menjadi tiga grup yang memiliki nilai kunci berbeda 0, 1, dan 2.

let sequence = seq { 1 .. 100 }

let printSeq seq1 = Seq.iter (printf "%A ") seq1

let sequences3 =
    sequences
    |> Seq.groupBy (fun index ->
        if (index % 3 = 0) then 0
        elif (index % 3 = 1) then 1
        else 2)

sequences3 |> printSeq

Outputnya sebagai berikut.

(1, seq [1; 4; 7; 10; ...]) (2, seq [2; 5; 8; 11; ...]) (0, seq [3; 6; 9; 12; ...])

Anda dapat membuat urutan yang menghilangkan elemen duplikat dengan memanggil Seq.distinct. Atau Anda dapat menggunakan Seq.distinctBy, yang memanggil fungsi pembuat kunci pada setiap elemen. Urutan yang dihasilkan berisi elemen dari urutan asli yang memiliki kunci unik; kemudian elemen yang menghasilkan kunci duplikat ke elemen sebelumnya dibuang.

Contoh kode berikut menunjukkan penggunaan Seq.distinct. Seq.distinct ditunjukkan dengan menghasilkan urutan yang mewakili angka biner, kemudian menunjukkan bahwa satu-satunya elemen yang berbeda adalah 0 dan 1.

let binary n =
    let rec generateBinary n =
        if (n / 2 = 0) then [n]
        else (n % 2) :: generateBinary (n / 2)

    generateBinary n
    |> List.rev
    |> Seq.ofList

printfn "%A" (binary 1024)

let resultSequence = Seq.distinct (binary 1024)
printfn "%A" resultSequence

Kode berikut menunjukkan Seq.distinctBy dengan memulai pada urutan yang berisi angka negatif dan positif, dan menggunakan fungsi nilai absolut sebagai fungsi pembuat kunci. Urutan yang dihasilkan kehilangan semua angka positif yang sesuai dengan angka negatif dalam urutan, karena angka negatif muncul lebih awal dalam urutan. Oleh karena itu, angka negatif dipilih, dan bukan angka positif yang memiliki nilai absolut yang sama, atau kunci.

let inputSequence = { -5 .. 10 }
let printSeq seq1 = Seq.iter (printf "%A ") seq1

printfn "Original sequence: "
printSeq inputSequence

printfn "\nSequence with distinct absolute values: "
let seqDistinctAbsoluteValue = Seq.distinctBy (fun elem -> abs elem) inputSequence
printSeq seqDistinctAbsoluteValue

Urutan Baca-saja dan Cache

Seq.readonly membuat salinan urutan baca-saja. Seq.readonly berguna ketika Anda memiliki kumpulan baca-tulis, seperti array, dan tidak ingin mengubah koleksi asli. Fungsi ini dapat digunakan untuk menjaga enkapsulasi data. Dalam contoh kode berikut, jenis yang berisi array dibuat. Properti mengekspos array, tetapi tidak memunculkan array, melainkan memunculkan urutan yang dibuat dari array dengan menggunakan Seq.readonly.

type ArrayContainer(start, finish) =
    let internalArray = [| start .. finish |]
    member this.RangeSeq = Seq.readonly internalArray
    member this.RangeArray = internalArray

let newArray = new ArrayContainer(1, 10)
let rangeSeq = newArray.RangeSeq
let rangeArray = newArray.RangeArray

// These lines produce an error:
//let myArray = rangeSeq :> int array
//myArray[0] <- 0

// The following line does not produce an error.
// It does not preserve encapsulation.
rangeArray[0] <- 0

Seq.cache membuat versi urutan yang disimpan. Gunakan Seq.cache untuk menghindari evaluasi ulang urutan, atau ketika Anda memiliki beberapa utas yang menggunakan urutan, tetapi Anda harus memastikan bahwa setiap elemen ditindaklanjuti satu kali saja. Ketika Anda memiliki urutan yang digunakan oleh beberapa utas, Anda dapat memiliki satu utas yang mencacah dan menghitung nilai pada urutan aslinya, dan utas yang tersisa dapat menggunakan urutan cache.

Melakukan Komputasi pada Urutan

Operasi aritmatika sederhana sama seperti yang ada di daftar, seperti Seq.average, Seq.sum, Seq.averageBy, Seq.sumBy, dan sebagainya.

Seq.fold, Seq.reduce, dan Seq.scan sama seperti fungsi terkait yang tersedia untuk daftar. Urutan mendukung subset dari variasi penuh pada fungsi-fungsi ini yang mencantumkan dukungan. Untuk informasi dan contoh selengkapnya, lihat Daftar.

Lihat juga