F # - Chuỗi

Chuỗi, giống như danh sách cũng đại diện cho một tập hợp các giá trị có thứ tự. Tuy nhiên, các phần tử trong một chuỗi hoặc biểu thức chuỗi được tính toán khi được yêu cầu. Chúng không được tính toán cùng một lúc và vì lý do này, chúng được sử dụng để biểu diễn cấu trúc dữ liệu vô hạn.

Xác định trình tự

Các chuỗi được xác định bằng cú pháp sau:

seq { expr }

Ví dụ,

let seq1 = seq { 1 .. 10 }

Tạo chuỗi và biểu thức chuỗi

Tương tự như danh sách, bạn có thể tạo chuỗi bằng cách sử dụng phạm vi và khả năng hiểu.

Biểu thức trình tự là những biểu thức bạn có thể viết để tạo chuỗi. Những điều này có thể được thực hiện -

  • Bằng cách chỉ định phạm vi.
  • Bằng cách chỉ định phạm vi với mức tăng hoặc giảm.
  • Bằng cách sử dụng yield từ khóa để tạo ra các giá trị trở thành một phần của chuỗi.
  • Bằng cách sử dụng toán tử →.

Các ví dụ sau đây chứng minh khái niệm -

ví dụ 1

(* Sequences *)
let seq1 = seq { 1 .. 10 }

(* ascending order and increment*)
printfn "The Sequence: %A" seq1
let seq2 = seq { 1 .. 5 .. 50 }

(* descending order and decrement*)
printfn "The Sequence: %A" seq2

let seq3 = seq {50 .. -5 .. 0}
printfn "The Sequence: %A" seq3

(* using yield *)
let seq4 = seq { for a in 1 .. 10 do yield a, a*a, a*a*a }
printfn "The Sequence: %A" seq4

Khi bạn biên dịch và thực thi chương trình, nó sẽ tạo ra kết quả sau:

The Sequence: seq [1; 2; 3; 4; ...]
The Sequence: seq [1; 6; 11; 16; ...]
The Sequence: seq [50; 45; 40; 35; ...]
The Sequence: seq [(1, 1, 1); (2, 4, 8); (3, 9, 27); (4, 16, 64); ...]

Ví dụ 2

Chương trình sau đây in ra các số nguyên tố từ 1 đến 50:

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

let primeIn50 = seq { for n in 1..50 do if isprime n then yield n }
for x in primeIn50 do
   printfn "%d" x

Khi bạn biên dịch và thực thi chương trình, nó sẽ tạo ra kết quả sau:

1
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47

Các thao tác cơ bản trên trình tự

Bảng sau đây trình bày các thao tác cơ bản trên kiểu dữ liệu trình tự:

Giá trị Sự miêu tả
nối thêm: seq <'T> → seq <' T> → seq <'T> Bao bọc hai kiểu liệt kê đã cho dưới dạng một kiểu liệt kê nối liền nhau.
trung bình: seq <^ T> → ^ T Trả về giá trị trung bình của các phần tử trong dãy.
AverageBy: ('T → ^ U) → seq <' T> → ^ U Trả về giá trị trung bình của các kết quả được tạo bằng cách áp dụng hàm cho từng phần tử của dãy.
cache: seq <'T> → seq <' T> Trả về một chuỗi tương ứng với phiên bản đã lưu trong bộ nhớ cache của chuỗi đầu vào.
diễn viên: IEnumerable → seq <'T> Bao bọc một Hệ thống được đánh máy lỏng lẻo. Trình tự tập hợp dưới dạng trình tự đã nhập.
chọn: ('T →' U option) → seq <'T> → seq <' U> Áp dụng chức năng đã cho cho từng phần tử của danh sách. Trả về danh sách bao gồm các kết quả cho từng phần tử mà hàm trả vềSome.
thu thập: ('T →' Tập hợp) → seq <'T> → seq <' U> Áp dụng hàm đã cho cho mỗi phần tử của dãy và nối tất cả các kết quả.
so sánhVới: ('T →' T → int) → seq <'T> → seq <' T> → int So sánh hai chuỗi bằng cách sử dụng hàm so sánh đã cho, từng phần tử.
concat: seq <'Bộ sưu tập> → seq <' T> Kết hợp các kiểu liệt kê đã cho dưới dạng một kiểu liệt kê nối đơn lẻ.
countBy: ('T →' Key) → seq <'T> → seq <' Key * int> Áp dụng hàm tạo khóa cho từng phần tử của một dãy và trả về một dãy mang lại các khóa duy nhất và số lần xuất hiện của chúng trong dãy ban đầu.
delay: (unit → seq <'T>) → seq <' T> Trả về một trình tự được xây dựng từ đặc điểm kỹ thuật bị trễ đã cho của một trình tự.
khác biệt: seq <'T> → seq <' T> Trả về một chuỗi không chứa các mục nhập trùng lặp theo phép so sánh hàm băm và đẳng thức chung trên các mục nhập. Nếu một phần tử xuất hiện nhiều lần trong chuỗi thì các lần xuất hiện sau đó sẽ bị loại bỏ.
Riêng biệtBy: ('T →' Phím) → seq <'T> → seq <' T> Trả về một chuỗi không chứa các mục nhập trùng lặp theo phép so sánh hàm băm và đẳng thức chung trên các khóa được trả về bởi hàm tạo khóa đã cho. Nếu một phần tử xuất hiện nhiều lần trong chuỗi thì các lần xuất hiện sau đó sẽ bị loại bỏ.
trống: seq <'T> Tạo một chuỗi trống.
chính xácOne: seq <'T> →' T Trả về phần tử duy nhất của dãy.
tồn tại: ('T → bool) → seq <' T> → bool Kiểm tra xem có phần tử nào của dãy thỏa mãn vị từ đã cho hay không.
tồn tại2: ('T1 →' T2 → bool) → seq <'T1> → seq <' T2> → bool Kiểm tra xem có cặp phần tử tương ứng nào của dãy đầu vào thỏa mãn vị từ đã cho hay không.
bộ lọc: ('T → bool) → seq <' T> → seq <'T> Trả về một tập hợp mới chỉ chứa các phần tử của tập hợp mà vị từ đã cho trả về true.
find: ('T → bool) → seq <' T> → 'T Trả về phần tử đầu tiên mà hàm đã cho trả về true.
findIndex: ('T → bool) → seq <' T> → int Trả về chỉ số của phần tử đầu tiên mà hàm đã cho trả về true.
gấp: ('Trạng thái →' T → 'Trạng thái) →' Trạng thái → seq <'T> →' Trạng thái Áp dụng một hàm cho từng phần tử của tập hợp, xâu chuỗi một đối số tích lũy thông qua tính toán. Nếu hàm đầu vào là f và các phần tử là i0 ... iN, thì hàm này tính f (... (fs i0) ...) iN.
forall: ('T → bool) → seq <' T> → bool Kiểm tra xem tất cả các phần tử của dãy có thỏa mãn vị từ đã cho hay không.
forall2: ('T1 →' T2 → bool) → seq <'T1> → seq <' T2> → bool Kiểm tra tất cả các cặp phần tử được rút ra từ hai dãy thỏa mãn vị từ đã cho. Nếu một dãy ngắn hơn dãy kia thì các phần tử còn lại của dãy dài hơn bị bỏ qua.
groupBy: ('T →' Key) → seq <'T> → seq <' Key * seq <'T >> Áp dụng một hàm tạo khóa cho từng phần tử của một chuỗi và tạo ra một chuỗi các khóa duy nhất. Mỗi khóa duy nhất cũng chứa một chuỗi tất cả các phần tử khớp với khóa này.
head: seq <'T> →' T Trả về phần tử đầu tiên của dãy.
init: int → (int → 'T) → seq <' T> Tạo một chuỗi mới, khi được lặp lại, trả về các phần tử liên tiếp bằng cách gọi hàm đã cho, với số lượng đã cho. Kết quả của việc gọi hàm không được lưu, tức là, hàm được áp dụng lại khi cần thiết để tạo lại các phần tử. Hàm được chuyển chỉ mục của mục đang được tạo.
initInfinite: (int → 'T) → seq <' T> Tạo một chuỗi mới, khi được lặp lại, sẽ trả về các phần tử kế tiếp bằng cách gọi hàm đã cho. Kết quả của việc gọi hàm không được lưu, tức là, hàm sẽ được áp dụng lại khi cần thiết để tạo lại các phần tử. Hàm được chuyển chỉ mục của mục đang được tạo.
isEmpty: seq <'T> → bool Kiểm tra xem một chuỗi có bất kỳ phần tử nào không.
iter: ('T → đơn vị) → seq <' T> → đơn vị Áp dụng chức năng đã cho cho từng phần tử của tập hợp.
iter2: ('T1 →' T2 → đơn vị) → seq <'T1> → seq <' T2> → đơn vị Áp dụng chức năng đã cho cho hai tập hợp đồng thời. Nếu một dãy ngắn hơn dãy kia thì các phần tử còn lại của dãy dài hơn bị bỏ qua.
iteri: (int → 'T → đơn vị) → seq <' T> → đơn vị Áp dụng chức năng đã cho cho từng phần tử của tập hợp. Số nguyên được truyền vào hàm cho biết chỉ số của phần tử.
cuối cùng: seq <'T> →' T Trả về phần tử cuối cùng của dãy.
length: seq <'T> → int Trả về độ dài của chuỗi.
map: ('T →' U) → seq <'T> → seq <' U> Tạo một tập hợp mới có các phần tử là kết quả của việc áp dụng hàm đã cho cho từng phần tử của tập hợp. Hàm đã cho sẽ được áp dụng khi các phần tử được yêu cầu sử dụng phương thức MoveNext trên các liệt kê được truy xuất từ ​​đối tượng.
map2: ('T1 →' T2 → 'U) → seq <' T1> → seq <'T2> → seq <' U> Tạo một tập hợp mới có các phần tử là kết quả của việc áp dụng hàm đã cho cho các cặp phần tử tương ứng từ hai chuỗi. Nếu một chuỗi đầu vào ngắn hơn chuỗi đầu vào kia thì các phần tử còn lại của chuỗi dài hơn sẽ bị bỏ qua.
mapi: (int → 'T →' U) → seq <'T> → seq <' U> Tạo một tập hợp mới có các phần tử là kết quả của việc áp dụng hàm đã cho cho từng phần tử của tập hợp. Chỉ số số nguyên được chuyển đến hàm cho biết chỉ số (từ 0) của phần tử được chuyển đổi.
tối đa: seq <'T> →' T Trả về giá trị lớn nhất trong số tất cả các phần tử của dãy, được so sánh bằng cách sử dụng Operator.max.
maxBy: ('T →' U) → seq <'T> →' T Trả về giá trị lớn nhất trong tất cả các phần tử của dãy, được so sánh bằng cách sử dụng Operator.max trên kết quả của hàm.
tối thiểu: seq <'T> →' T Trả về giá trị thấp nhất trong số tất cả các phần tử của dãy, được so sánh bằng cách sử dụng Operator.min.
minBy: ('T →' U) → seq <'T> →' T Trả về giá trị thấp nhất trong số tất cả các phần tử của dãy, được so sánh bằng cách sử dụng Operator.min trên kết quả của hàm.
thứ n: int → seq <'T> →' T Tính toán phần tử thứ n trong tập hợp.
ofArray: 'T mảng → seq <' T> Xem mảng đã cho dưới dạng một chuỗi.
ofList: 'T list → seq <' T> Xem danh sách đã cho dưới dạng một chuỗi.
theo cặp: seq <'T> → seq <' T * 'T> Trả về một chuỗi của mỗi phần tử trong chuỗi đầu vào và phần tử tiền nhiệm của nó, ngoại trừ phần tử đầu tiên chỉ được trả về như phần tử trước của phần tử thứ hai.
pick: ('T →' U option) → seq <'T> →' U Áp dụng hàm đã cho cho các phần tử kế tiếp, trả về giá trị đầu tiên trong đó hàm trả về Some giá trị.
chỉ đọc: seq <'T> → seq <' T> Tạo một đối tượng chuỗi mới ủy quyền cho đối tượng chuỗi đã cho. Điều này đảm bảo trình tự gốc không thể được phát hiện lại và biến đổi bởi một kiểu đúc. Ví dụ: nếu cho một mảng, chuỗi được trả về sẽ trả về các phần tử của mảng, nhưng bạn không thể ép kiểu đối tượng chuỗi được trả về vào một mảng.
giảm: ('T →' T → 'T) → seq <' T> → 'T Áp dụng một hàm cho mỗi phần tử của chuỗi, xâu chuỗi một đối số tích lũy thông qua tính toán. Bắt đầu bằng cách áp dụng hàm cho hai phần tử đầu tiên. Sau đó, cung cấp kết quả này vào hàm cùng với phần tử thứ ba, v.v. Trả lại kết quả cuối cùng.
quét: ('Trạng thái →' T → 'Trạng thái) →' Trạng thái → seq <'T> → seq <' Trạng thái> Giống như Seq.fold, nhưng tính toán theo yêu cầu và trả về chuỗi kết quả trung gian và cuối cùng.
singleton: 'T → seq <' T> Trả về một chuỗi chỉ mang lại một mục.
bỏ qua: int → seq <'T> → seq <' T> Trả về một chuỗi bỏ qua một số phần tử được chỉ định của dãy cơ bản và sau đó trả về các phần tử còn lại của chuỗi.
bỏ quaWhile: ('T → bool) → seq <' T> → seq <'T> Trả về một chuỗi mà khi được lặp lại, bỏ qua các phần tử của chuỗi bên dưới trong khi vị từ đã cho trả về true, và sau đó thu được các phần tử còn lại của dãy.
sắp xếp: seq <'T> → seq <' T> Mang lại một chuỗi được sắp xếp theo các phím.
sortBy: ('T →' Key) → seq <'T> → seq <' T> Áp dụng chức năng tạo khóa cho từng phần tử của một chuỗi và mang lại một chuỗi được sắp xếp theo các khóa. Các khóa được so sánh bằng cách sử dụng so sánh chung như được triển khai bởi Operators.compare.
tổng: seq <^ T> → ^ T Trả về tổng các phần tử trong dãy.
sumBy Trả về tổng các kết quả được tạo ra bằng cách áp dụng hàm cho từng phần tử của dãy.
lấy: int → seq <'T> → seq <' T> Trả về các phần tử đầu tiên của dãy với số lượng được chỉ định.
takeWhile: ('T → bool) → seq <' T> → seq <'T> Trả về một chuỗi mà khi được lặp lại, sẽ mang lại các phần tử của chuỗi bên dưới trong khi vị từ đã cho trả về true, và sau đó không trả về phần tử nào nữa.
toArray: seq <'T> →' T [] Tạo một mảng từ bộ sưu tập đã cho.
toList: seq <'T> →' T list Tạo danh sách từ bộ sưu tập đã cho.
cắt ngắn: int → seq <'T> → seq <' T> Trả về một chuỗi mà khi được liệt kê trả về không quá một số phần tử được chỉ định.
tryFind: ('T → bool) → seq <' T> → 'T tùy chọn Trả về phần tử đầu tiên mà hàm đã cho trả về true, hoặc là None nếu không có phần tử như vậy tồn tại.
tryFindIndex: ('T → bool) → seq <' T> → int option Trả về chỉ số của phần tử đầu tiên trong chuỗi thỏa mãn vị từ đã cho, hoặc None nếu không có phần tử như vậy tồn tại.
tryPick: ('T →' U option) → seq <'T> →' U option Áp dụng hàm đã cho cho các phần tử kế tiếp, trả về giá trị đầu tiên trong đó hàm trả về Some giá trị.
mở ra: ('Trạng thái →' T * 'Tùy chọn trạng thái) →' Trạng thái → seq <'T> Trả về một chuỗi chứa các phần tử được tạo bởi phép tính đã cho.
trong đó: ('T → bool) → seq <' T> → seq <'T> Trả về một tập hợp mới chỉ chứa các phần tử của tập hợp mà vị từ đã cho trả về true. Một từ đồng nghĩa với Seq.filter.
windowed: int → seq <'T> → seq <' T []> Trả về một chuỗi mang lại cửa sổ trượt chứa các phần tử được vẽ từ chuỗi đầu vào. Mỗi cửa sổ được trả về dưới dạng một mảng mới.
zip: seq <'T1> → seq <' T2> → seq <'T1 *' T2> Kết hợp hai chuỗi thành một danh sách các cặp. Hai trình tự không nhất thiết phải có độ dài bằng nhau - khi một trình tự cạn kiệt, bất kỳ phần tử còn lại nào trong trình tự khác sẽ bị bỏ qua.
zip3: seq <'T1> → seq <' T2> → seq <'T3> → seq <' T1 * 'T2 *' T3> Kết hợp ba chuỗi thành một danh sách các bộ ba. Các trình tự không cần phải có độ dài bằng nhau - khi một trình tự sử dụng hết thì bất kỳ phần tử còn lại nào trong các trình tự khác sẽ bị bỏ qua.

Các ví dụ sau đây chứng minh việc sử dụng một số chức năng ở trên -

ví dụ 1

Chương trình này tạo ra một chuỗi trống và lấp đầy nó sau -

(* Creating sequences *)
let emptySeq = Seq.empty
let seq1 = Seq.singleton 20

printfn"The singleton sequence:"
printfn "%A " seq1
printfn"The init sequence:"

let seq2 = Seq.init 5 (fun n -> n * 3)
Seq.iter (fun i -> printf "%d " i) seq2
printfn""

(* converting an array to sequence by using cast *)
printfn"The array sequence 1:"
let seq3 = [| 1 .. 10 |] :> seq<int>
Seq.iter (fun i -> printf "%d " i) seq3
printfn""

(* converting an array to sequence by using Seq.ofArray *)
printfn"The array sequence 2:"
let seq4 = [| 2..2.. 20 |] |> Seq.ofArray
Seq.iter (fun i -> printf "%d " i) seq4
printfn""

Khi bạn biên dịch và thực thi chương trình, nó sẽ tạo ra kết quả sau:

The singleton sequence:
seq [20]
The init sequence:
0 3 6 9 12
The array sequence 1:
1 2 3 4 5 6 7 8 9 10
The array sequence 2:
2 4 6 8 10 12 14 16 18 20

Xin lưu ý rằng -

  • Phương thức Seq.empty tạo ra một chuỗi trống.

  • Phương thức Seq.singleton tạo ra một chuỗi chỉ gồm một phần tử được chỉ định.

  • Phương thức Seq.init tạo ra một chuỗi mà các phần tử được tạo bằng cách sử dụng một hàm đã cho.

  • Phương thức Seq.ofArray và Seq.ofList <'T> tạo chuỗi từ mảng và danh sách.

  • Phương thức Seq.iter cho phép lặp qua một chuỗi.

Ví dụ 2

Phương thức Seq.unfold tạo ra một chuỗi từ một hàm tính toán có trạng thái và biến đổi nó để tạo ra từng phần tử tiếp theo trong chuỗi.

Hàm sau tạo ra 20 số tự nhiên đầu tiên:

let seq1 = Seq.unfold (fun state -> if (state > 20) then None else Some(state, state + 1)) 0
printfn "The sequence seq1 contains numbers from 0 to 20."
for x in seq1 do printf "%d " x
printfn" "

Khi bạn biên dịch và thực thi chương trình, nó sẽ tạo ra kết quả sau:

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

Ví dụ 3

Phương thức Seq.truncate tạo một chuỗi từ một chuỗi khác, nhưng giới hạn chuỗi ở một số phần tử được chỉ định.

Phương thức Seq.take tạo một chuỗi mới có chứa một số phần tử được chỉ định từ đầu chuỗi.

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

printfn"The original sequence"
Seq.iter (fun i -> printf "%d " i) mySeq
printfn""

printfn"The truncated sequence"
Seq.iter (fun i -> printf "%d " i) truncatedSeq
printfn""

printfn"The take sequence"
Seq.iter (fun i -> printf "%d " i) takeSeq
printfn""

Khi bạn biên dịch và thực thi chương trình, nó sẽ tạo ra kết quả sau:

The original sequence
3 6 9 12 15 18 21 24 27 30
The truncated sequence
3 6 9 12 15
The take sequence
3 6 9 12 15