2010-04-13 26 views
13

Trong Haskell, có một hàm "lấy danh sách n" trả về các phần tử n đầu tiên từ một danh sách. Ví dụ: "sum (take 3 xs)" tổng hợp ba phần tử đầu tiên trong danh sách xs. F # có tương đương không? Tôi mong đợi nó sẽ là một trong những chức năng Danh sách, nhưng tôi không thể phát hiện ra bất kỳ thứ gì có vẻ phù hợp.F # có tương đương với việc sử dụng của Haskell không?

Trả lời

15

Vâng, nó được gọi là Seq.take. Cách sử dụng có vẻ giống hệt với số điện thoại của Haskell: Seq.taketính nguồn. Để sử dụng nó trên danh sách, trước tiên hãy sử dụng List.toSeq. (Cập nhật: Rõ ràng từ các ý kiến, điều này là không cần thiết.)

+0

Điều đó dường như chính xác những gì tôi đang tìm kiếm. Thử nghiệm ngay bây giờ. :) – McMuttons

+13

Thực ra, hành động của haskell có tác dụng như Seq.truncate, chứ không phải Seq.take. – sepp2k

+2

Vì danh sách kế thừa từ IEnumerable, bạn không phải chuyển đổi nó thành chuỗi đầu tiên từ những gì tôi có thể thấy. Sử dụng Seq.take trên một danh sách làm việc tốt. – McMuttons

39

Để làm rõ một vài điều, sự khác biệt giữa Seq.takeSeq.truncate (như được chỉ ra bởi @ sepp2k) là một trong những thứ hai sẽ cung cấp cho bạn một chuỗi trả lại số tiền tối đa tối đa số phần tử bạn đã chỉ định (nhưng nếu độ dài của chuỗi ít hơn, nó sẽ cung cấp cho bạn ít phần tử hơn).

Trình tự tạo ra Seq.take chức năng sẽ ném ngoại lệ nếu bạn cố truy cập phần tử vượt quá độ dài của danh sách gốc (Lưu ý rằng hàm Seq.take không ném ngoại lệ ngay lập tức, vì kết quả là chuỗi được tạo lười biếng).

Ngoài ra, bạn không cần chuyển đổi danh sách thành chuỗi một cách rõ ràng. Dưới trang bìa, list<'a> là lớp .NET kế thừa từ loại seq<'a>, là giao diện. Loại seq<'a> thực sự chỉ là một bí danh loại cho IEnumerable<'a>, do đó, nó được thực hiện bởi tất cả các bộ sưu tập khác (bao gồm mảng, danh sách có thể thay đổi, v.v.). Các mã sau đây sẽ làm việc tốt:

let list = [ 1 .. 10 ] 
let res = list |> Seq.take 5 

Tuy nhiên, nếu bạn muốn có được một kết quả của loại list<int> bạn sẽ cần phải chuyển đổi chuỗi lại một danh sách (vì một danh sách là loại hình cụ thể hơn một chuỗi):

let resList = res |> List.ofSeq 

tôi không chắc chắn lý do tại sao F # thư viện không cung cấp List.take hoặc List.truncate. Tôi đoán mục tiêu là tránh thực hiện lại toàn bộ các chức năng cho tất cả các loại bộ sưu tập, vì vậy những nơi thực hiện chuỗi là đủ tốt khi làm việc với một loại bộ sưu tập cụ thể hơn chỉ có trong mô-đun Seq (nhưng đó chỉ là phỏng đoán của tôi) ...)

+0

Làm rõ rõ. – McMuttons

+0

@McMuttons: Cảm ơn! Tôi không chắc mình có nên đăng nó hay không, bởi vì hầu hết mọi thứ đã được đề cập trong các ý kiến ​​.. Vì vậy, tôi rất vui vì nó đã được sử dụng! –

1

Seq.take hoạt động, như những người khác đã nêu, nhưng tất cả các hoạt động Seq trên danh sách đều có tính phí. Trong trường hợp của Seq.take, nó không đáng ngạc nhiên, vì danh sách phải được sao chép.

Đáng chú ý hơn, ví dụ: Seq.concat trên danh sách mất nhiều thời gian hơn List.concat. Tôi cho rằng điều đó ngụ ý rằng bạn không chỉ truy cập vào danh sách dưới dạng seq khi bạn gọi một hàm Seq.xxx, nhưng danh sách đó được sao chép/chuyển đổi thành một Seq đằng sau hậu trường.

chỉnh sửa: Lý do tôi đi đến kết luận trên, là băng ghế dự bị này sử dụng F # tương tác:

#time "on";; 
let lists = [for i in 0..5000000 -> [i..i+1]];; 
Seq.length (Seq.concat lists);; 
List.length (List.concat lists);; 

Trên máy tính của tôi, phiên bản List.length mất khoảng 1,9 giây, trong khi phiên bản Seq.length mất khoảng 3.8 giây (thời gian ngắn nhất của một vài phép thử lặp lại các dòng chiều dài, không bao gồm dòng tạo danh sách).

+3

Tôi không nghĩ rằng điều này là chính xác. 'danh sách <'t>' triển khai giao diện 'seq <'t>' để không cần chuyển đổi, cũng không có lý do gì để mong đợi một bản sao được thực hiện. Ngoài ra, 'Seq.take' hoạt động một cách uể oải, trong khi' List.take' không thể, vì vậy trong một danh sách dài, các hoạt động chuỗi sẽ gần như chắc chắn sẽ nhanh hơn nếu chỉ có mặt trước của chuỗi kết quả là cần thiết. Tuy nhiên, có thể thực hiện một hàm 'List.take' thông qua kết hợp mẫu sẽ hoạt động tốt hơn so với triển khai' Seq.take' liệt kê danh sách nếu bạn muốn truy cập háo hức tất cả các phần tử trong danh sách kết quả. – kvb

+1

Kết luận của tôi về các chuyển đổi diễn ra có thể là sai, nhưng có điều gì đó đang diễn ra và phải mất thêm thời gian. Tôi đã chỉnh sửa bài đăng của mình và thêm một số thời gian. – Batibix

Các vấn đề liên quan