2009-01-27 36 views
12

Lộn xộn xung quanh với 'chức năng mở rộng' cho mô-đun Danh sách. (Tôi đã dành nhiều thời gian phát triển 'mapfold' - những chủ đề một ắc như lần, nhưng sử dụng nó như một tham số để tạo ra giá trị mới như bản đồ - sau đó phát hiện ra rằng đó là những gì List.scan_left không)Sản phẩm chéo của hai danh sách

Đối với thế hệ của thử nghiệm dữ liệu, tôi cần phải làm một sản phẩm chéo của hai danh sách, Đây là những gì tôi đã đưa ra:

///Perform cross product of two lists, return tuple 
let crossproduct l1 l2 = 
    let product lst v2 = List.map (fun v1 -> (v1, v2)) lst 
    List.map_concat (product l1) l2 

Đây có phải là bất kỳ tốt, hoặc là đã có một số cách tốt hơn để làm điều này?

Câu hỏi tương tự với bộ phim này:

///Perform cross product of three lists, return tuple 
let crossproduct3 l1 l2 l3 = 
    let tuplelist = crossproduct l1 l2 //not sure this is the best way... 
    let product3 lst2 v3 = List.map (fun (v1, v2) -> (v1, v2, v3)) lst2 
    List.map_concat (product3 tuplelist) l3 
+0

Xem câu hỏi liên quan tại đây: http://stackoverflow.com/questions/935996/calculating-the-cartesian-product-of-a-list-of-numbers-with-f – Benjol

Trả lời

22

tùy chọn khác là sử dụng F # "biểu thức chuỗi" và viết một cái gì đó như thế này:

let crossproduct l1 l2 = 
    seq { for el1 in l1 do 
      for el2 in l2 do 
      yield el1, el2 };; 

(trên thực tế, nó gần như là điều tương tự như những gì bạn đã viết, bởi vì 'for .. in .. do' trong biểu thức tuần tự có thể được xem dưới dạng map_concat). Điều này làm việc với các trình tự (lười), nhưng nếu bạn muốn làm việc với các danh sách, bạn chỉ cần quấn mã bên trong [...] thay vì bên trong seq {...}.

+1

Và được viết như vậy, crossproduct3 trở nên tầm thường – Benjol

1

Hàm crossproduct của bạn có vẻ tốt (bạn có thể nhận thấy từ khóa "trong" bị thiếu). Tôi thích phiên bản crossproduct3 này tốt hơn, nhưng đó chỉ là tôi:

let crossproduct3 l1 l2 l3 = 
List.map_concat 
(fun z -> 
(List.map_concat (fun y -> List.map (fun x -> (x, y, z)) l3) l2)) l1;; 

Chức năng của bạn có độ phức tạp về thuật toán tương đương.

Cuối cùng, khi sử dụng tích vectơ trên một danh sách rõ ràng trống, bạn có thể nhấn vào value restriction (khoảng, một hạn chế đó đảm bảo trình biên dịch chỉ suy luận kiểu đa hình cho một giá trị cú pháp), đó là đặc biệt nghiêm ngặt trong F #. Giải pháp là để chú thích các cuộc gọi sử dụng một danh sách trống, theo cách sau (nếu bạn muốn danh sách thứ hai được tạo thành từ số nguyên):

(crossproduct [3; 4] [] : (int * int) list) 
0

tôi một cái gì đó gần đây cần thiết tương tự - Tôi đã phải nén một danh sách các trình tự để một chuỗi các danh sách - vì vậy [(a1,a2,a3,...);(b1,b2,b3,...);(c1,c2,c3,...)] -> ([a1;b1;c1], [a2;b2;c3], ...)

đoạn mã dưới đây sẽ làm điều này:

let rec listZip (sl : 'a seq list) = 
     seq { 
      match sl with 
      | [] -> yield [] 
      | hd::tl -> 
       for h in hd do 
       for t in listZip tl do 
       yield (h::t) 
    } 
4

Chỉ cần đi qua một giải pháp khá thanh lịch này sử dụng biểu thức tính toán:

type Product() = 
    member this.Bind (l,f) = List.collect f l  
    member this.Return n = [n] 

let enumeratedPizzas = 
    Product() { 
    let! x = ["New York";"Chicago"] 
    let! y = ["Pepperoni";"Sausage"] 
    let! z = ["Cheese";"Double Cheese"] 
    return x,y,z 
    } 

Bằng Techneilogy, được sao chép từ fssnip.net, hãy nhấp vào liên kết để xem mã nhận xét.

+2

Tôi đã xem qua câu hỏi này, khá cổ xưa - đáng lưu ý rằng đây là _exactly_ cùng một khuôn mẫu như các biểu thức trình tự sử dụng, chỉ với cú pháp hơi xấu xí. Tôi đã viết (rất nhiều) về các tùy chọn cú pháp khác nhau trong http://www.cl.cam.ac.uk/~tp322/drafts/notations.html –

1

Tôi đã sử dụng Benjol câu trả lời trong một thời gian cho đến khi tôi thấy rằng bạn có thể làm được điều tương tự với Linq.giải pháp Benjol của có lẽ vẫn là thanh lịch nhất nhưng nếu có ai muốn có một giải pháp mà bạn có thể sử dụng với C# cũng sau đó ở đây bạn đi:

query { 
    for i in [1, 2] do 
    for j in [3, 4] do 
    select (i, j) 
} 

Đó là gần như chính xác giống như giải pháp Tomas Petricek của trừ giải pháp không cần được lồng vào nhau for vòng để nó đơn giản hơn một chút.

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