[英]Haskell: Splitting list into tuple of two new lists
我很難弄清楚如何將一個 Int 列表拆分成一個包含兩個新列表的元組,這樣每個元素(從第一個開始)進入第一個列表,每個其他元素進入第二個列表。
像這樣:
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])
我正在嘗試以遞歸方式(使用警衛)完成此操作,並且僅使用單個參數 xs
這是我不斷收到錯誤消息的方法:
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))
您的split
函數返回一對,但在最后一種情況下,您在split
的結果上使用++
。 這將是一個類型錯誤,因為++
適用於列表,而不是對。 還有一個類型錯誤,因為fst
和snd
是挑選一對元素的函數,但是你使用它們是一種奇怪的方式。
此外,使用模式匹配而不是使用長度。 此外,不需要測試長度是否為 2 的情況,因為一般情況會刪除 2 個元素,這會將您帶到空列表的基本情況。
您還可以通過在類型中使用類型變量a
而不是Int
來使您的函數更通用。
[編輯]:添加代碼
split :: [a] -> ([a], [a])
split [] = ([], [])
split [x] = ([x], [])
split (x:y:xys) = (x:xs, y:ys) where (xs, ys) = split xys
另一種方法是使用相互遞歸。 它很容易閱讀:
split xs = (odds xs, evens xs)
odds (x:xs) = x : evens xs
odds xs = []
evens xs = odds (drop 1 xs)
Haskell Blow Your Mind wiki 有一些內襯:
-- 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))
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)) ([], [])
兩個替代版本:
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..]
這是一個簡單的解決方案:
通過獲取列表 [a],我們可以將其拆分為兩個新列表,首先我們首先聲明空列表會發生什么,在這里您可以選擇返回錯誤“空列表”或僅返回兩個空列表作為如下所示,在列表中有一個元素的情況下,我們將其拆分為一個包含 x 的列表和一個空列表 ([x],[ ])。 在列表大小 > 1 的情況下,我們計算 n(列表的長度“除以”2),然后我們“獲取”新列表中的前 n 個元素並從原始列表 xs 中“刪除”n 個元素。
split :: [a] -> ([a],[a])
split [] = ([],[])
split [x] = ([x],[])
split xs = (take n xs, drop n xs)
where n = (length xs) `div` 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)
如果您正在尋找某種替代方法來執行此操作,以下是一種這樣的實現:
split xs =
let (a,b) = partition (odd . snd) (zip xs [1..])
in ( (map fst a), (map fst b))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.