Khi nào sử dụng một chuỗi trong F # thay vì một danh sách?


82

Tôi hiểu rằng danh sách thực sự chứa các giá trị và một chuỗi là bí danh cho IEnumerable<T>. Trong quá trình phát triển F # thực tế, khi nào tôi nên sử dụng một chuỗi thay vì một danh sách?

Dưới đây là một số lý do tôi có thể thấy khi nào một trình tự sẽ tốt hơn:

  • Khi tương tác với các ngôn ngữ hoặc thư viện .NET khác yêu cầu IEnumerable<T>.
  • Cần biểu diễn một dãy vô hạn (có lẽ không thực sự hữu ích trong thực tế).
  • Cần đánh giá lười biếng.

Có những người khác?


3
Tôi thấy chuỗi vô hạn rất hữu ích và phổ biến. Ví dụ: System.Random.Next () đã là một "chuỗi vô hạn". Thường thì tôi muốn thứ gì đó tạo ra nhiều yếu tố nếu cần. Gần đây tôi đã viết một Tetris trong F # và đại diện cho việc tạo khối dưới dạng một chuỗi vô hạn: nó sẽ tạo ra nhiều như yêu cầu khi trò chơi tiếp tục.
Asik

2
@Dr_Asik Lưu ý rằng một seqđược tạo theo cách đó sẽ tạo ra các số ngẫu nhiên khác nhau mỗi khi bạn nhìn vào nó. Đó rõ ràng có thể là nguồn gốc của các lỗi không xác định được ...
JD

Câu trả lời:


96

Tôi nghĩ rằng bản tóm tắt của bạn để chọn thời điểm Seqlà khá tốt. Dưới đây là một số điểm bổ sung:

  • Sử dụng Seqtheo mặc định khi viết các hàm, vì sau đó chúng hoạt động với bất kỳ bộ sưu tập .NET nào
  • Sử dụng Seqnếu bạn cần các chức năng nâng cao như Seq.windowedhoặcSeq.pairwise

Tôi nghĩ chọn Seqtheo mặc định là tùy chọn tốt nhất, vậy khi nào tôi sẽ chọn loại khác?

  • Sử dụng Listkhi bạn cần xử lý đệ quy bằng cách sử dụng các head::tailmẫu
    (để triển khai một số chức năng không có trong thư viện chuẩn)

  • Sử dụng Listkhi bạn cần một cấu trúc dữ liệu bất biến đơn giản mà bạn có thể xây dựng từng bước
    (ví dụ: nếu bạn cần xử lý danh sách trên một chuỗi - để hiển thị một số thống kê - và đồng thời tiếp tục xây dựng danh sách trên một chuỗi khác khi bạn nhận được nhiều giá trị hơn tức là từ một dịch vụ mạng)

  • Sử dụng Listkhi bạn làm việc với danh sách ngắn - danh sách là cấu trúc dữ liệu tốt nhất để sử dụng nếu giá trị thường đại diện cho một danh sách trống , vì nó rất hiệu quả trong trường hợp đó

  • Sử dụng Arraykhi bạn cần tập hợp lớn các kiểu giá trị
    (mảng lưu trữ dữ liệu trong một khối bộ nhớ phẳng, vì vậy chúng tiết kiệm bộ nhớ hơn trong trường hợp này)

  • Sử dụng Arraykhi bạn cần truy cập ngẫu nhiên hoặc hiệu suất cao hơn (và cục bộ bộ nhớ cache)


1
Cảm ơn rất nhiều - chính xác là những gì tôi đã theo đuổi. Thật khó hiểu khi học F # để tìm ra lý do tại sao có hai yếu tố này (list & seq) cung cấp cho bạn chức năng tương tự.
dodgy_coder

3
"Sử dụng List[...] khi bạn cần một cấu trúc dữ liệu bất biến đơn giản mà bạn có thể xây dựng từng bước [...] và đồng thời tiếp tục xây dựng danh sách trên một chuỗi khác [...]" Bạn có thể giải thích thêm về ý nghĩa ở đây / cách thức hoạt động? Cảm ơn.
Narfanar

2
@Noein Ý tưởng là bạn luôn có thể lặp trên danh sách (họ là không thay đổi) nhưng bạn có thể tạo danh sách mới sử dụng x::xsmà không vi phạm bất kỳ người lao động hiện có mà có thể là trong quá trình iterating quaxs
Tomas Petricek

29

Cũng thích seqkhi:

  • Bạn không muốn giữ tất cả các phần tử trong bộ nhớ cùng một lúc.

  • Hiệu suất không quan trọng.

  • Bạn cần phải làm điều gì đó trước và sau khi liệt kê, ví dụ: kết nối với cơ sở dữ liệu và đóng kết nối.

  • Bạn không nối (lặp đi lặp lại Seq.appendsẽ làm tràn).

Ưu tiên listkhi:

  • Có ít yếu tố.

  • Bạn sẽ chi tiêu và cắt đầu rất nhiều.

Cả seqcũng listlà tốt cho xử lý song song nhưng điều đó không nhất thiết có nghĩa là họ là xấu cả. Ví dụ, bạn có thể sử dụng một trong hai để biểu thị một nhóm nhỏ các hạng mục công việc riêng biệt sẽ được thực hiện song song.


"Cả seq và danh sách đều không tốt cho song song": bạn có thể mở rộng thêm tại sao seq không tốt cho song song không? Điều gì tốt cho song song sau đó, chỉ mảng?
Asik

5
Mảng @Dr_Asik là tốt nhất vì bạn có thể chia nhỏ chúng một cách đệ quy và giữ lại vị trí tốt của tham chiếu. Cây là tốt nhất tiếp theo vì bạn cũng có thể chia nhỏ chúng nhưng vị trí tham chiếu không tốt cho lắm. Danh sách và trình tự không hợp lệ vì bạn không thể chia nhỏ chúng. Nếu bạn chọn các phần tử thay thế thì bạn sẽ có được vị trí tham chiếu tồi tệ nhất có thể. Guy Steele đã thảo luận về các tập hợp tuyến tính cản trở sự song song mặc dù ông chỉ xem xét công việc và độ sâu chứ không phải cục bộ (hay còn gọi là độ phức tạp của bộ nhớ cache ). labs.oracle.com/projects/plrg/Publications/…
JD

12

Chỉ một điểm nhỏ: SeqArraytốt hơn so Listvới song song.

Bạn có một vài lựa chọn: PSeq từ F # PowerPack, Array.Parallel mô-đun và Async.Parallel (tính không đồng bộ). Danh sách rất tệ khi thực hiện song song do tính chất tuần tự của nó ( head::tailthành phần).


Đó là một điểm tốt - tình huống mà tôi đã nghĩ đến là khi bạn cần xây dựng bộ sưu tập trên một luồng (tức là khi bạn nhận các giá trị từ một số dịch vụ) và sử dụng nó từ một luồng khác (tức là để tính toán thống kê và hiển thị nó). Tôi đồng ý rằng đối với xử lý song song (khi bạn đã có tất cả dữ liệu trong bộ nhớ), có Arrayhoặc PSeqtốt hơn nhiều.
Tomas Petricek

1
Tại sao bạn nói điều đó seqtốt hơn listcho song song? seqcũng là khủng khiếp để thực hiện song song do tính chất liên tục của họ ...
JD

7

danh sách nhiều chức năng hơn, thân thiện với toán học. khi mỗi phần tử bằng nhau thì 2 danh sách bằng nhau.

trình tự không.

let list1 =  [1..3]
let list2 =  [1..3]
printfn "equal lists? %b" (list1=list2)

let seq1 = seq {1..3}
let seq2 = seq {1..3}
printfn "equal seqs? %b" (seq1=seq2)

nhập mô tả hình ảnh ở đây


5

Bạn nên luôn hiển thị Seqtrong các API công khai của mình. Sử dụng ListArraytriển khai nội bộ của bạn.


Đó có phải là vì chúng hoạt động tốt với các ngôn ngữ .NET khác không? tức là vì a Seqđược xem như là một IEnumerable<T>?
dodgy_coder

Không, vì thực hành thiết kế tốt. Tiết lộ càng nhiều thông tin càng tốt, không hơn.
Aleš Roubíček,

Ok, bình luận công bằng, đây cũng là một thực tiễn tốt cho mã C # - tức là một hàm tốt nhất có thể được định nghĩa là IEnumerable <T> chứ không phải là List <T> nặng hơn chẳng hạn.
dodgy_coder

1
Tôi đồng ý trong bối cảnh của cấu trúc trả về có thể thay đổi (ví dụ: lỗ hổng thiết kế này trong .NET: msdn.microsoft.com/en-us/library/afadtey7.aspx ) hoặc các API có thể được sử dụng từ các ngôn ngữ .NET khác nhưng tôi không đồng ý nói chung, một phần vì seqquá tệ cho song song.
JD
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.