2012-02-01 32 views
5

Tôi có một số danh sách - mỗi trường hợp chứa 9 số dấu phẩy động. Điều tôi thực sự cần làm là tạo một danh sách mới lấy phần tử đầu tiên từ mỗi danh sách của tôi và thêm chúng với nhau làm phần tử đầu tiên, sau đó thêm phần tử thứ hai từ mỗi danh sách làm phần tử thứ hai của tôi, v.v.Cách thành ngữ để "hợp nhất" nhiều danh sách có cùng độ dài trong F #?

có hiệu quả, nếu dữ liệu của tôi trông giống như sau:

List1 = [a1; b1; c1; d1; e1; f1; g1; h1; i1] 
List2 = [a2; b2; c2; d2; e2; f2; g2; h2; i2] 
... 
Listn = [an; bn; cn; dn; en; fn; gn; hn; in] 

Sau đó, tôi cần phải tạo ra một danh sách mới Listx mà

Listx = [a1 + a2 + ... + an; b1 + b2 + ... + bn; ... ] 

số lượng danh sách tôi sẽ được sáp nhập sẽ khác nhau (đôi khi tôi chỉ có thể có một danh sách gồm 9 số và đôi khi hơn 100 danh sách, luôn luôn 9 yếu tố dài), vì vậy tôi đã tự hỏi nếu có ai có lời khuyên nào về một cách thành ngữ tốt đẹp để làm điều này?

Tôi đã xem this questionthis one nhưng cả hai dường như ủng hộ bước trung gian lập chỉ mục các phần tử của tôi trước và sau đó sử dụng nhóm. Điều này khiến tôi khó chịu vì a) Tôi cảm thấy có thể có một giải pháp thanh lịch hơn cho trường hợp cụ thể của tôi và b) hiệu suất có thể là vấn đề sau này - Tôi không muốn tối ưu hóa sớm, nhưng tôi cũng không muốn tự mình quay ở chân.

+2

" * hiệu suất có thể là một vấn đề sau này - tôi không muốn tối ưu hóa sớm, nhưng tôi cũng không muốn tự bắn mình vào chân. * "Tôi đồng ý với tình cảm này, nhưng đáng lưu ý rằng nếu bạn đóng gói đúng cách các chức năng sau đó thay đổi việc thực hiện sau này nếu hiệu suất là một vấn đề nên không đau và không ảnh hưởng đến phần còn lại của mã của bạn. – ildjarn

Trả lời

7

Đây là một giải pháp mà hoạt động trên một danh sách liệt kê với cùng chiều dài:

let mapN f = function 
    | [] -> [] 
    | xss -> List.reduce (List.map2 f) xss 

let inline merge xss = mapN (+) xss 

// Usage 
let yss = List.init 1000 (fun i -> [i+1..i+9]) 
let ys = merge yss 
+1

Bạn cần đánh dấu 'sumAll'' inline' để nó hoạt động với 'float' và các kiểu số khác. – Daniel

+0

Cảm ơn bạn đã chỉ ra, cố định. – pad

+0

Hoàn hảo! Cảm ơn bạn –

1

Dưới đây là một cách tiếp cận:

let merge lists = 
    let rec impl acc lists = 
    match List.head lists with 
    | [] -> List.rev acc 
    | _ -> let acc' = (lists |> List.map List.head |> List.reduce (+))::acc 
      let lists' = List.map List.tail lists 
      impl acc' lists' 
    impl [] lists 

Một số lưu ý:

  • List.reduce (+) được sử dụng thay vì List.sum hoặc List.sumBy vì sau chỉ hoạt động đối với các loại số trong khi (+) có thể hoạt động, ví dụ: string.
  • merge được giả định là loại int list list -> int list thay vì chung chung do sự tinh tế của toán tử cách + hoạt động. Nếu bạn chỉ cần điều này để làm việc cho một loại duy nhất, và loại đó là khôngint (ví dụ float), sau đó thêm một loại chú thích để merge sẽ đủ:

    let merge (lists:float list list) = 
    
  • merge thể được đánh dấu inline và sau đó sẽ làm việc cho bất kỳ loại nào hỗ trợ nhà điều hành +, nhưng điều này sẽ dẫn đến rất nhiều bloat trong IL của bạn nếu có nhiều hơn một hoặc hai trang web gọi. Nếu bạn có nhiều loại cần phải làm việc với merge và tất cả được biết trước, thì cách giải quyết tốt ở đây là tạo mergeinline (và có thể là private) rồi xác định các chức năng cụ thể theo loại khác nhau được thực hiện dưới dạng chung merge:

    let inline merge lists = 
        let rec impl acc lists = 
        match List.head lists with 
        | [] -> List.rev acc 
        | _ -> let acc' = (lists |> List.map List.head |> List.reduce (+))::acc 
          let lists' = List.map List.tail lists 
          impl acc' lists' 
        impl [] lists 
    
    let mergeInts (lists:int list list) = merge lists 
    let mergeFloats (lists:float list list) = merge lists 
    let mergeStrings (lists:string list list) = merge lists 
    

    Nếu sau đó bạn chỉ gọi loại cụ thể merge s, khối lượng IL sẽ không đáng kể.

  • Cuối cùng, nếu hiệu suất là thực sự là một mối quan ngại, sau đó sử dụng mảng thay vì danh sách.
2

tôi muốn đi qua một cái gì đó dễ dàng hơn như một ma trận:

let merge xss = 
    let m = matrix xss 
    List.map (m.Column >> Seq.sum) [0..m.NumCols-1] 
1
// Shamelessly stolen from: 
// http://hackage.haskell.org/packages/archive/base/latest/doc/html/src/Data-List.html#transpose 
let rec transpose = function 
    | [] -> [] 
    | ([] :: xss) -> transpose xss 
    | ((x :: xs) :: xss) -> (x :: List.map List.head xss) :: transpose (xs :: List.map List.tail xss) 

let fuse = transpose >> List.map List.sum 

printfn "%A" (fuse [[3; 4]; [1; 90]; [34; 89]]) // prints [38; 183] 
0

Dưới đây là một một trong lót thay thế với giá trị mặc định khi danh sách của danh sách là rỗng:

let sumVertically length = List.fold (List.map2 (+)) (List.replicate length 0) 

//usage 
//stolen from pad's answer 
let listOfLists = List.init 1000 (fun i -> [i+1..i+9]) 
sumVertically 9 listOfLists 
Các vấn đề liên quan