2011-09-14 8 views
5

Intsのリストを2つの新しいリストを含むタプルに分割する方法を理解することが難しいです。最初のリストから始まるすべての要素が最初のリストに入り、 2番目の要素の他の要素。Haskell:リストを2つの新しいリストのタプルに分割する

ので、同じように:

:私は(ガード付き)を再帰的にこれを達成しようと、単一の引数はxs

を使用してい

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]) 

これは、取得エラーメッセージを保持し、私のアプローチです

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

は皆さんありがとうございました! – Shabu

+1

答えの1つを受け入れる必要があります。 –

答えて

14

split関数はペアを返しますが、最後のケースではの結果に++を使用しています0。 ++はペアではなくリスト上で動作するため、タイプエラーになります。 fstsndはペアの要素を選択する関数なのでタイプエラーがありますが、それらを使用しているのは変です。

さらに、lengthを使用する代わりにパターンマッチングを使用します。また、長さが2であるかどうかをテストするケースは必要ありません。一般的なケースでは、空のリストのベースケースに移動する2つの要素が削除されるためです。

タイプにIntの代わりにaという型変数を使用すると、より一般的な関数にすることもできます。

[編集]:コードを追加しました

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

また、 'split(z:zs)=(z:ys、xs)ここで(xs、ys)= split zs'! – Zantier

0

最後の節に誤りがあります。あなたは再帰呼び出しから結果を得てから、最初と2番目の要素をそれらに追加する必要があります。

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

これは、この関数を書くにはまだ恐ろしい方法です。 – augustss

+0

はい、あなたは絶対に正しいです。しかし、私はこれを再帰的に(警備員を使って)実行し、単一の引数xsだけを使用して質問に従おうとしています。 – bravit

+1

これでもO(n^2)ではなくO(n)の複雑さを得ることができます。 – augustss

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

しかし、あなたは折り目を使用する必要があります。

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

そのコードは彼が求めていることをしませんし、パターンマッチングの代わりに 'head'と' tail'を使うので悪いです。 – augustss

+0

私のコードが間違った結果を与える入力の例を挙げてください。 (そして、あなたは再帰とガードのバージョンやfoldrのバージョンについて言及していますか?)パターンマッチングは 'head'と' tail'よりも良いでしょうが、OPはガードを使いたいと思っています--- **この場合** ** ---パターンマッチングを排除します(パターンマッチの後にガードする余地はありません)。 – dave4420

+1

申し訳ありませんが、私は間違っていることを取り返します。コーヒーが足りません。 :) – augustss

0

あなたは以下、これを行うには、いくつかの代替方法を探している場合にはそのような実装である:

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

2種類の代替バージョン:

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

これを行う別の方法は、相互再帰による方法です。 、

split xs = (odds xs, evens xs) 

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

evens xs = odds (drop 1 xs) 
2

ハスケルBlow Your Mindウィキいくつかのいずれかライナーがあります:それは読むことが非常に簡単に出てくる

-- 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))