2011-09-14 52 views
5

Tôi đang gặp khó khăn khi tìm cách chia danh sách Ints thành một bộ chứa hai danh sách mới, sao cho mọi thành phần (bắt đầu bằng danh sách đầu tiên) vào danh sách đầu tiên yếu tố khác trong giây.Haskell: Tách danh sách thành tuple của hai danh sách mới

Giống như vậy:

split [] = ([],[]) 
split [1] = ([1],[]) 
split [1,2] = ([1],[2]) 
split [1,2,3] = ([1,3],[2]) 
split [1,2,3,4] = ([1,3],[2,4]) 

Tôi đang cố gắng để thực hiện điều này một cách đệ quy (với lính gác) và chỉ sử dụng các xs đối số duy nhất

Đây là cách tiếp cận của tôi mà giữ nhận thông báo lỗi:

split :: [Int] -> ([Int],[Int]) 
split xs | length(xs) == 0 = ([],[]) 
     | length(xs) == 1 = (xs !! 0 : [],[]) 
     | length(xs) == 2 = (xs !! 0 : [], xs !! 1 : []) 
     | otherwise = (fst ++ xs !! 0, snd ++ xs !! 1) ++ split(drop 2 xs))  
+0

Cảm ơn các bạn! – Shabu

+1

Bạn nên chấp nhận một trong các câu trả lời. –

Trả lời

14

Hàm split của bạn trả về một cặp, nhưng trong trường hợp cuối cùng bạn đang sử dụng ++ trên kết quả của split. Đó sẽ là lỗi loại, vì ++ hoạt động trên danh sách chứ không phải cặp. Ngoài ra còn có lỗi loại vì fstsnd là các chức năng để chọn các thành phần của một cặp, nhưng bạn đang sử dụng chúng là một cách kỳ lạ.

Ngoài ra, hãy sử dụng đối sánh mẫu thay vì sử dụng độ dài. Ngoài ra, trường hợp bạn kiểm tra nếu độ dài là 2 là không cần thiết, vì trường hợp chung loại bỏ 2 phần tử sẽ đưa bạn xuống trường hợp cơ sở của danh sách trống.

Bạn cũng có thể làm cho chức năng của mình tổng quát hơn bằng cách sử dụng biến loại a thay vì Int trong loại.

[Chỉnh sửa]: Nhập mã

split :: [a] -> ([a], [a]) 
split [] = ([], []) 
split [x] = ([x], []) 
split (x:y:xys) = (x:xs, y:ys) where (xs, ys) = split xys 
+1

Cách khác, 'split (z: zs) = (z: ys, xs) trong đó (xs, ys) = chia zs'! – Zantier

0

Có một sai lầm trong mệnh đề cuối cùng. Bạn phải nhận kết quả từ cuộc gọi đệ quy và sau đó thêm các phần tử đầu tiên và thứ hai vào chúng.

split :: [Int] -> ([Int],[Int]) 
split xs | length(xs) == 0 = ([],[]) 
     | length(xs) == 1 = (xs !! 0 : [],[]) 
     | length(xs) == 2 = (xs !! 0 : [], xs !! 1 : []) 
     | otherwise = let (fst, snd) = split(drop 2 xs) in 
        (xs !! 0 : fst, xs !! 1 : snd) 
+0

Đây vẫn là một cách khủng khiếp để viết chức năng này. – augustss

+0

Vâng, bạn hoàn toàn đúng. Nhưng tôi đang cố gắng theo dõi câu hỏi 'để thực hiện điều này một cách đệ quy (với bảo vệ) và chỉ sử dụng đối số đơn xs' – bravit

+1

Bạn vẫn có thể làm điều đó và nhận được độ phức tạp O (n) thay vì O (n^2). – augustss

3
split :: [a] -> ([a], [a]) 
split xs | null xs = ([], []) 
     | otherwise = (head xs : snd pair, fst pair) 
    where pair = split (tail xs) 

Nhưng bạn nên sử dụng một lần:

split :: [a] -> ([a], [a]) 
split = foldr (\x (ys, zs) -> (x : zs, ys)) ([], []) 
+0

Mã đó không làm những gì anh ta yêu cầu, và nó cũng là xấu bởi vì nó sử dụng 'đầu' và' đuôi' thay vì khớp mẫu. – augustss

+0

Bạn có thể đưa ra ví dụ về đầu vào khi mã của tôi cho kết quả không đúng không. (Và bạn đang đề cập đến phiên bản đệ quy-và-bảo vệ hay phiên bản foldr?) Tôi đồng ý rằng mô hình phù hợp sẽ tốt hơn so với 'đầu' và' đuôi', nhưng OP dường như muốn sử dụng bảo vệ, mà --- ** trong trường hợp này ** --- loại trừ khớp mẫu (không còn gì để bảo vệ sau khi khớp mẫu). – dave4420

+1

Xin lỗi, tôi lấy lại điều đó là sai. Không đủ cà phê. :) – augustss

0

Trong trường hợp bạn đang tìm kiếm một số cách khác để làm điều này, dưới đây là một trong những thực hiện như:

split xs = 
    let (a,b) = partition (odd . snd) (zip xs [1..]) 
    in ((map fst a), (map fst b)) 
1

Hai phiên bản thay thế:

split = conv . map (map snd) . groupWith (even.fst) . zip [0..] where 
    conv [xs,ys] = (xs,ys) 

split xs = (ti even xs, ti odd xs) where 
    ti f = map snd . filter (f.fst) . zip [0..] 
5

Một cách khác để làm điều này là với đệ quy lẫn nhau. Nó đi ra rất dễ đọc:

split xs = (odds xs, evens xs) 

odds (x:xs) = x : evens xs 
odds xs  = [] 

evens xs = odds (drop 1 xs) 
2

Các Haskell Blow Your Mind wiki, có một số một lót:

-- splitting in two (alternating) 
-- "1234567" -> ("1357", "246") 

-- the lazy match with ~ is necessary for efficiency, especially enabling 
-- processing of infinite lists 
foldr (\a ~(x,y) -> (a:y,x)) ([],[]) 

(map snd *** map snd) . partition (even . fst) . zip [0..] 

transpose . unfoldr (\a -> toMaybe (null a) (splitAt 2 a)) 
Các vấn đề liên quan