簡體   English   中英

Haskell:將列表拆分為兩個新列表的元組

[英]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的結果上使用++ 這將是一個類型錯誤,因為++適用於列表,而不是對。 還有一個類型錯誤,因為fstsnd是挑選一對元素的函數,但是你使用它們是一種奇怪的方式。

此外,使用模式匹配而不是使用長度。 此外,不需要測試長度是否為 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM