2010-10-14 39 views
17

Không thể tìm ra cách để kết hợp hai danh sách theo cách sau trong Haskell:sáp nhập hai danh sách trong Haskell

INPUT: [1,2,3,4,5] [11,12,13,14] 

OUTPUT: [1,11,2,12,3,13,4,14,5] 
+6

Thông thường, bạn tìm hiểu thêm nếu bạn giải thích những gì bạn đã cố gắng và tại sao nó không hiệu quả, cách mà mọi người có thể làm một số điền-in-the- những khoảng trống thay vì chỉ cho bạn một đoạn mã. –

+0

Liên quan: [Danh sách các danh sách xen kẽ trong Haskell] (http://stackoverflow.com/q/14186433/2157640) – Palec

Trả lời

39
merge :: [a] -> [a] -> [a] 
merge xs  []  = xs 
merge []  ys  = ys 
merge (x:xs) (y:ys) = x : y : merge xs ys 
+0

Tôi mới làm quen với lập trình hàm và mã giúp tôi tự hỏi điều này: Tối ưu hóa cuộc gọi đuôi có áp dụng trong đó không hình thức đệ quy quá? –

+1

Không, không. Cuộc gọi đuôi là (:), và nó không cần tối ưu hóa. – Ingo

+0

Có một phiên bản lười hơn về điều này trong [câu trả lời khác] (http://stackoverflow.com/a/3987188/2157640). Nó lười trong tham số thứ hai. – Palec

6

EDIT: Hãy nhìn vào câu trả lời và ý kiến ​​của Ed'ka !

Một khả năng khác:

merge xs ys = concatMap (\(x,y) -> [x,y]) (zip xs ys) 

Hoặc, nếu bạn thích applicative:

merge xs ys = concat $ getZipList $ (\x y -> [x,y]) <$> ZipList xs <*> ZipList ys 
+3

Yea, tệ, chỉ hoạt động trên các danh sách có độ dài bằng nhau. – bogatyrjov

21

Vậy tại sao bạn nghĩ đơn giản (. Concat transpose) "là không đủ xinh đẹp"? Tôi cho rằng bạn đã thử một cái gì đó như:

merge :: [[a]] -> [a] 
merge = concat . transpose 

merge2 :: [a] -> [a] -> [a] 
merge2 l r = merge [l,r] 

Vì vậy, bạn có thể tránh đệ quy rõ ràng (so với câu trả lời đầu tiên) và vẫn đơn giản hơn câu trả lời thứ hai. Vì vậy, những hạn chế là gì?

+0

Ah, tôi quên mất việc chuyển đổi và bỏ lỡ nhận xét. Rất đẹp, +1 (Nhưng tôi không nhất thiết phải nói rằng nó dễ dàng hơn nhiều so với giải pháp đầu tiên của tôi.) – danlei

+3

Đồng ý. Giải pháp của bạn có lẽ thậm chí còn đơn giản hơn .. Vấn đề thực sự với nó mặc dù nó không phải là chính xác 100%: cho các danh sách có độ dài khác nhau (như trong đầu vào mẫu từ câu hỏi) nó không hoạt động như mong đợi (tailing '5' bị thiếu). –

+0

Tốt bắt! Tôi bỏ qua 5 trong đầu ra mẫu. Tôi sẽ cập nhật câu trả lời của tôi với một con trỏ để trả lời và bình luận của bạn. Cảm ơn! – danlei

50

Tôi muốn đề xuất một phiên bản lazier của merge:

merge [] ys = ys 
merge (x:xs) ys = x:merge ys xs 

Đối với một trường hợp ví dụ sử dụng, bạn có thể kiểm tra một gần đây SO câu hỏi về lazy generation of combinations.
Phiên bản trong câu trả lời được chấp nhận là không cần thiết nghiêm ngặt trong đối số thứ hai và đó là những gì được cải thiện ở đây.

+0

Vâng, điều đó đặt tất cả các yếu tố của ys vào cuối, do đó, nó không hoạt động. Nhưng tôi nghĩ ý của bạn là đảo ngược thứ tự của hai phương trình đầu tiên trong giải pháp của andri. – Yitz

+13

Không, nó cũng giống nhau - thay đổi giữa mỗi danh sách. Lưu ý rằng 'xs' và' ys' được hoán đổi trong cuộc gọi đệ quy. –

+1

Đó là một giải pháp tuyệt vời! Tôi muốn tôi có thể nghĩ về điều gì đó tương tự như bản thân mình – bogatyrjov

-2
-- ++ 
pp [] [] = [] 
pp [] (h:t) = h:pp [] t 
pp (h:t) [] = h:pp t [] 
pp (h:t) (a:b) = h : pp t (a:b) 
+1

Giải pháp này không đúng. Dòng cuối cùng phải là 'pp (h: t) (a: b) = h: a: pp t b'. – bisserlis

4

Chắc chắn một trường hợp cho một Unfold:

interleave :: [a] -> [a] -> [a] 
interleave = curry $ unfoldr g 
    where 
    g ([], []) = Nothing 
    g ([], (y:ys)) = Just (y, (ys, [])) 
    g (x:xs, ys) = Just (x, (ys, xs)) 
+0

Mã ban đầu của bạn không hoạt động; 'interleave [] [1,2,3]' sẽ cho '[]'. Tôi nghĩ rằng nó sẽ hoạt động ngay bây giờ. – dfeuer

+0

trường hợp khác cho bạn ['unfoldr''] (http://stackoverflow.com/q/24519530/849891) apomorphism! (sau đó nó sẽ tương đương với [câu trả lời này] (http://stackoverflow.com/a/3987188/849891) ở trên). –

+0

@dfeuer (nhận xét ở trên) –

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